Как оптимизировать производительность одновременной записи файлов в C#

Я пытаюсь оптимизировать производительность, создавая множество маленьких файлов на SSD-диске.

ConcurrentBag<string[]> cb = new ConcurrentBag<string[]>();
cb.AsParallel().ForAll(fa => File.WriteAllText(fa[0], fa[1]));

Общее количество ConcurrentBag<string[]> = 80048, cb.Sum(gbc => Encoding.UTF8.GetByteCount( gbc[1] ) ); возвращает 393441217 байт.

Где-то еще я делаю xml.Save();, который создает файл ~750MB.

Первая ситуация занимает 3 минуты и 30 секунд. Вторые 20 секунд.

Я понимаю, что есть некоторые накладные расходы для обработки всех отдельных операций записи, но 3 минуты и 30 секунд все еще кажутся немного длинными. Я уже пробовал распараллеливание с помощью forall, что помогло довольно хорошо (до этого требовалось 6-8 минут). Какие еще модификации я могу добавить в свой код, чтобы оптимизировать производительность массового создания файла?

2 ответа

Решение

На самом деле, несколько одновременных операций ввода-вывода могут сильно замедлить процесс, особенно на традиционных дисках. Я рекомендую использовать ConcurrentQueue для записи нескольких файлов.

Также вы можете переключиться на StreamWriter и контролировать размер буфера для увеличения скорости записи:

    ConcurrentQueue<string[]> concurrentQueue = new ConcurrentQueue<string[]>();

    // populate with some data
    for (int i = 0; i < 5000; i++)
    {
        concurrentQueue.Enqueue(new string[] { Guid.NewGuid().ToString(), Guid.NewGuid().ToString() });
    }

    while (true)
    {
        string[] currentElement;
        bool success = concurrentQueue.TryDequeue(out currentElement);
        if (success)
        {
            const int BufferSize = 65536;  // change it to your needs
            using (var sw = new StreamWriter(currentElement[0], true, Encoding.UTF8, BufferSize))
            {
                sw.Write(currentElement[1]);
            }
        }
    }

Вы должны также попытаться использовать ForEach вместо ForAll. Вы можете найти некоторые веские причины в посте http://reedcopsey.com/2010/02/03/parallelism-in-net-part-8-plinqs-forall-method/

почтовая директива

Метод расширения ForAll следует использовать только для обработки результатов параллельного запроса, возвращаемого выражением PLINQ.

Другие вопросы по тегам