Как оптимизировать производительность одновременной записи файлов 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();, который создает файл ~ 750 МБ.

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

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


person BigChief    schedule 04.08.2015    source источник


Ответы (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]);
            }
        }
    }
person Daniel Luberda    schedule 04.08.2015
comment
Как определить подходящий размер буфера? Это не традиционный диск, а SSD, следует определить это в первую очередь... У вас есть пример concurrentqueue с File.WriteAllText или StreamWriter? Также я пробовал с размером буфера = 16384 (4 * по умолчанию), но это вызвало исключение из памяти. - person BigChief; 04.08.2015
comment
Я по-прежнему рекомендую вам переключиться на ConcurrentQueue, я обновлю свой ответ примером. SSD тоже страдают (но намного меньше). См. technet.microsoft.com/en-us/library/cc938632.aspx и stackoverflow.com/questions/8803515/ - person Daniel Luberda; 04.08.2015

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

руководство по почте

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

person silver    schedule 04.08.2015