FileStream.BeginWrite преимущества перед FileStream.Write? - PullRequest
6 голосов
/ 12 октября 2011

Мне нужно сделать серию записей в один и тот же файл, но в разных местах файла. Я хочу добиться этого с максимально возможной производительностью и поэтому рассмотрел синхронные методы FileStream.Write и асинхронный FileStream.BeginWrite.

Синхронная реализация тривиальна и просто вызывает FileStream. Запишите необходимое количество раз в цикле. Асинхронная версия вызывает FileStream.BeginWrite в цикле, а затем выполняет WaitHandle.WaitAll, чтобы заблокировать, пока все они не будут завершены. К моему удивлению, это работает медленнее, чем простая синхронная версия.

Я создал FileStream, используя правильный конструктор, чтобы я мог запросить асинхронную операцию, и я также протестировал свойство IAsyncResult.CompletedSynchronous, которое указывало на False, и поэтому они действительно работали в асинхронном режиме. Кажется, что единственным преимуществом использования BeginWrite является то, что вы не блокируете свой поток во время записи. Помимо этого преимущества, есть ли смысл использовать асинхронную версию?

Вот тестовый код, который я использовал для игры с асинхронным методом, может быть, есть очевидная ошибка?

        // Size of a chunk to be written to file
        var chunk = 1024 * 64;

        // Number of chunks to write async
        var reps = 32;

        // Create new file and set length
        var fs = new FileStream(@"C:\testfile.dat", 
                                FileMode.Create, FileAccess.ReadWrite, 
                                FileShare.None, chunk, true);
        fs.SetLength(chunk * reps);

        // Allocate resources
        byte[] bytes = new byte[chunk];
        WaitHandle[] handles = new WaitHandle[reps];

        for (int i = 0; i < reps; i++)
        {
            fs.Seek(chunk * i, SeekOrigin.Begin);
            handles[i] = fs.BeginWrite(bytes, 0, chunk, null, null).AsyncWaitHandle;
        }

        // Wait for all async operations to complete
        WaitHandle.WaitAll(handles);

        fs.Flush();
        fs.Close();

1 Ответ

20 голосов
/ 12 октября 2011

Запись файлов сильно оптимизирована в Windows.Вы фактически не пишете на диск, вы пишете в кэш файловой системы.Копия из памяти в память, работает со скоростью 5 гигабайт в секунду или лучше.Из кеша данные затем лениво записываются на диск.В свою очередь оптимизирован для минимизации числа перемещений головки записи.

Это почти невозможно оптимизировать с помощью асинхронных записей.Что действительно занимает больше времени, захват потока пула потоков, чтобы сделать обратный вызов, не приходит бесплатно.Преимущество асинхронности заключается в том, чтобы минимизировать задержки основного потока, а не сделать его более эффективным.Фактически вы получите выгоду только тогда, когда будете писать очень большие объемы данных.Больше чем поместится в кеш.В этот момент скорость записи будет падать со скалы с 5 ГБ / с до менее чем ~ 50 МБ / с, поскольку пространство в кэше может стать доступным только при скорости записи на диск.

Именно тогда, когда это произойдеттрудно предсказать.Это зависит от того, сколько оперативной памяти у машины и сколько ее требуется другим процессам.Вы в основном не беспокоитесь об этом, когда пишете гигабайт или меньше.И важно, чтобы у вас действительно было что-то полезное, когда асинхронная запись еще не завершена.Ожидание их завершения побеждает смысл его использования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...