Работа с большими коллекциями в db40 (.net) - PullRequest
3 голосов
/ 11 июля 2010

Я хотел бы использовать db4o в качестве серверной части реализации пользовательского кэша. Обычно моя программа предусматривает загрузку в память около 40 000 000 объектов и одновременную работу с ними. Очевидно, для этого требуется много памяти, и я подумал о том, чтобы, возможно, сохранить некоторые объекты (не в кеше) в базе данных db4o. Мои предварительные тесты показывают, что db4o работает немного медленнее, чем мне бы хотелось (около 1 000 000 объектов потребовалось 17 минут для сохранения). Однако я использовал самую базовую настройку.

Я делал что-то вроде этого:

using (var reader = new FileUnitReader(Settings, Dictionary, m_fileNameResolver, ObjectFactory.Resolve<DataValueConverter>(), ObjectFactory.Resolve<UnitFactory>()))
using (var db = Db4oEmbedded.OpenFile(Db4oEmbedded.NewConfiguration(), path))
{
    var timer = new Stopwatch();
    timer.Start();
    IUnit unit = reader.GetNextUnit();
    while (unit != null)
    {
        db.Store(unit);
        unit = reader.GetNextUnit();
    }
    timer.Stop()
    db.Close();

    var elapsed = timer.Elapsed;
}

Может кто-нибудь дать совет, как улучшить производительность в этом сценарии?

Ответы [ 2 ]

2 голосов
/ 11 июля 2010

Ну, я думаю, что есть несколько вариантов улучшения производительности в этой ситуации.

Я также обнаружил, что затраты на отражение в таких сценариях могут стать довольно большой частью. Так что вы можете попробовать быстрый отражатель для вашего случая. Обратите внимание, что FastReflector потребляет больше памяти. Однако в вашем сценарии это не будет иметь большого значения. Вы можете быстро отражатель, как это:

var config = Db4oEmbedded.NewConfiguration();
config.Common.ReflectWith(new FastNetReflector());

using(var container = Db4oEmbedded.OpenFile(config, fileName))
{
}

Когда я делал подобные крошечные «тесты», я обнаружил, что больший размер кэша также немного улучшает производительность, даже когда вы пишете в базу данных:

var config = Db4oEmbedded.NewConfiguration();
config.File.Storage = new CachingStorage(new FileStorage(), 128, 1024 * 4);

Другие заметки: Обработка транзакций в db4o на самом деле не оптимизирована для гигантских транзакций. Когда вы сохраняете 1'000'000 объектов в одной транзакции, фиксация может занять много лет или у вас заканчивается память. Поэтому вы можете захотеть совершать чаще. Например, коммит после каждых 100'000 сохраненных объектов. Конечно, вам нужно проверить, действительно ли это влияет на ваш сценарий.

1 голос
/ 12 июля 2010

Еще одно небольшое улучшение, которое вы можете попробовать:

Получить расширенный интерфейс, добавив .Ext () к вызову OpenFile ().

Очистить каждый объект после того, как вы его сохранили.

using (var db = Db4oEmbedded.OpenFile(Db4oEmbedded.NewConfiguration(), path).Ext())
// ....
db.Store(unit);
db.Purge(unit);
// ....

Таким образом вы уменьшите количество ссылок, которые db4o должен поддерживать в текущей транзакции.

Вероятно, у вас есть наибольший потенциал для еще одного большого улучшения, если вы играете с конфигурацией хранилища (это подключаемая файловая система ниже db4o.) Последние сборки 8.0 имеют лучшую реализацию кэша, которая не снижает производительность для кэша.обслуживание при работе с большим количеством страниц кеша.

Я предлагаю вам попробовать последнюю версию 8.0 с установкой кеша, которую Гэмлор предложил посмотреть, если это имеет значение:

config.File.Storage = new CachingStorage(new FileStorage(), 128, 1024 * 4);

Если это произойдет, вы можете попробовать гораздо более высокие цифры:

config.File.Storage = new CachingStorage(new FileStorage(), 1280, 1024 * 40);
...