Вкратце, необходимо обрабатывать очень большой объем текстовой информации, после чего сохранять на жесткий диск в виде zip архивов. Задача усложняется тем, что обработка должна происходить многопоточно.
Пользователь класса ZipSaver
...
ZipSaver saver = new ZipSaver(10000); // 10000 - это количество элементов, когда надо сохранять архив на жесткий диск
Parallel.ForEach(source, item => {
string workResult = ModifyItem(item);
saver.AddItem(workResult);
});
Часть класса ZipSaver (использует библиотеку Ionic ZipFile)
private ConcurrentQueue<ZipFile> _pool;
public void AddItem(string src){
ZipFile currentZipFile;
if(_pool.TryDequeue(out currentZipFile) == false){
currentZipFile = InitNewZipFile(); // если в пуле нет свободных архивов, создаем новый
}
currentZipFile.AddEntry(path, src); // добавление элемента в архив. path - просто путь в архиве
// если после добавления элемента в архив, достигнуто максимальное количество элементов,
// которое задается в конструкторе, сохраняем этот архив на жесткий диск,
// иначе - возвращаем архив в общий пул
if(currentZipFile.Enties.Count > _maxEntries){
SaveZip(currentZipFile); // выполняется порядочно времени
}else{
_pool.Enqueue(currentZipFile);
}
}
Можно, конечно, поиграть с цифрой максимального количества элементов в архиве, но от этого напрямую зависит и размер выходных архивов, что, в идеале, должно настраиваться. Сейчас ситуация такова, что при большом количестве элементов в исходной коллекции, которая обрабатывается в цикле, создается множество потоков, практический каждый из которых имеет "свой" инстанс ZipFile, что, естественно, приводит к переполнению оперативной памяти. Все работает неплохо, когда элементов мало, но, скажем с миллионом, оперативы может изыматься до 10 Гб.
Страшно подумать, что произойдет, если приложение запустить на машине с 4 Гб...
Вопрос к более опытным коллегам: как улучшить данный механизм сохранения, учитывая перечисленные недостатки?