2017-02-22 12 views
4

Почему код ниже результатов в:Почему .NET async ждет копию файла намного больше, чем процессор, чем синхронный вызов File.Copy()?

.NET async file copy

public static class Program 
{ 
    public static void Main(params string[] args) 
    { 
     var sourceFileName = @"C:\Users\ehoua\Desktop\Stuff\800MFile.exe"; 
     var destinationFileName = sourceFileName + ".bak"; 

     FileCopyAsync(sourceFileName, destinationFileName); 

     // The line below is actually faster and a lot less CPU-consuming 
     // File.Copy(sourceFileName, destinationFileName, true); 

     Console.ReadKey(); 
    } 

    public static async void FileCopyAsync(string sourceFileName, string destinationFileName, int bufferSize = 0x1000, CancellationToken cancellationToken = default(CancellationToken)) 
    { 
     using (var sourceFile = File.OpenRead(sourceFileName)) 
     { 
      using (var destinationFile = File.OpenWrite(destinationFileName)) 
      { 
       Console.WriteLine($"Copying {sourceFileName} to {destinationFileName}..."); 
       await sourceFile.CopyToAsync(destinationFile, bufferSize, cancellationToken); 
       Console.WriteLine("Done"); 
      } 
     } 
    } 
} 

Хотя File.Copy(): https://msdn.microsoft.com/en-us/library/system.io.file.copy(v=vs.110).aspx намного меньше процессора затрат:

Sync File Copy

Так есть еще реальный интерес, использующий async/ожидание для копирования файлов?

Я думал, что сохранение потока для копирования может стоить того, но функция File.Copy windows, похоже, выиграла битву с точки зрения CPU%. Некоторые утверждают, что это из-за реальной поддержки DMA, но все же я делаю что-нибудь, чтобы испортить выступления? Или есть что-то, что можно сделать для улучшения использования ЦП с помощью метода async?

+0

Быстрее ли это? – Steve

+0

@ Попробуйте не намного быстрее, немного, я все еще больше обеспокоен CPU%, что выглядит страшно. – Ehouarn

+1

Вероятно, это связано с различием между некоторыми способами, которые «File.Copy» реализуется в сравнении с вашим прямым потоковым использованием «File.OpenRead» и «File.OpenWrite». Я сомневаюсь, что это имеет какое-то отношение к синхронизации по сравнению с асинхронным. – Abion47

ответ

3

File.OpenRead(sourceFileName) эквивалентен new FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read), который в свою очередь эквивалентен public FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false), то есть с false для асинхронных операций ввода-вывода. Эквивалент относится к File.OpenWrite.

Как таковые, любые операции XXXAsync не будут использовать асинхронный ввод-вывод, но будут подделывать его, используя потоки потоков.

Так что он не получает ничего от асинхронного ввода-вывода и тратит по крайней мере один поток. У вас есть дополнительная блокировка потоков на вводе/выводе, чего вы хотели избежать. Обычно я ожидал, что async сам по себе будет работать немного медленнее, чем синхронизация (async обычно жертвует одноразовой скоростью для лучшей масштабируемости), но я определенно ожидаю, что это немного улучшится, если вообще произойдет, чем обернуть все это в Task.Run() ,

Я все еще не ожидал, что это будет так же плохо, но, возможно, защита от вредоносных программ вызывает беспокойство при написании .exe.

Вы бы надеялись, что лучше скопировать не-exe и с асинхронными потоками.

+0

На самом деле я упомянул об этом, комментируя ответ Ханса, параметр isAsync, который когда-то был установлен на true, резко уменьшил процессор%, но скорость кажется намного медленнее (мне потребовалось некоторое время, потому что я не сравнивал сначала скорость копирования файлов, а кажется, File.Copy, по-видимому, в 2 - 3 раза быстрее, чем асинхронный, но снова возьмите его с щепоткой соли). Я буду обновлять сообщение завтра с надлежащим бенчмаркингом. Я принимаю ваш ответ, поскольку он имеет большой смысл в дополнение к комментариям Эрика Липперта. – Ehouarn

+2

Я не был бы в ужасе от асинхронного копирования в пару раз медленнее, чем синхронизация. Я бы не использовал его, когда мне нужна более высокая пропускная способность одной операции; Я бы использовал его либо, когда я хотел сделать что-то еще в то же время, либо в веб-приложении, когда мне все равно, как быстро я обслуживаю один запрос, поскольку я делаю это очень быстро, я служу многие и сколько я могу служить одновременно. –

6

Это довольно абсурдные номера перформансов. Вы просто не измеряете то, что считаете себя. Это не должно быть больше, чем небольшая ошибка, простая копия памяти для памяти для кэшированных данных файла. Как и File.Copy(). Работает на ~ 35 гигабайт в секунду на машине с достойной памятью DDR3, поэтому не может быть больше нескольких десятков миллисекунд. Даже если файл не кэширован или на компьютере не хватает ОЗУ, вы все равно не можете получить такую ​​нагрузку на процессор, ваш код будет заблокирован в ожидании диска.

Что вы такое на самом деле видение является перформансом вашего установленного антивирусного продукта. Он всегда получает свое нижнее белье в комплекте, когда видит программы, управляющие исполняемыми файлами.

Простая проверка, отключение или исключение и повторная попытка.

+0

Согласившись с VS «вредоносным ПО», я хотел бы отметить, что диспетчер задач все еще указывает на то, что есть определенный рост с точки зрения процессора (плюс дешевый поклонник моего дешевого ноутбука страдает немного больше, когда используя async ждут). Опять же, реализация File.Copy, безусловно, лучше, но я менеджер, чтобы снизить асинхронную реализацию cpu% примерно на 75%, используя параметр isAsync. Я собираюсь проверить код corefx на GitHub, потому что это все еще слишком расплывчато, что происходит за кулисами. В любом случае спасибо за то, что он пролил свет на среду тестирования. – Ehouarn

+1

«То, что вы на самом деле видите, является перформансом вашего установленного антивирусного продукта». - Можете ли вы пояснить, что вы имеете в виду здесь? Вы говорите, что продукт против вредоносного ПО использует кучу процессора, который показан в Visual Studio? Или вы говорите, что другая программа заставляет программу @ EhouarnPerret использовать больше самого процессора? Я только что открыл Prime95, который привязывает все 8 моих ядер на 100% в диспетчере задач, но Visual Studio по-прежнему показывает ~ 13% использования процессора, то же самое число Task Manager показывает для моего 1 "ConsoleApplication" процесс. – Quantic

+2

Обычно вы не видите накладные расходы, вызванные антивирусными программами, потому что у вас нет роскоши профилировщика, наблюдающего за тем, что делает программа. Не стреляйте в посланника :) Нажмите кнопку «Спросить вопрос», если у вас есть другой случай, когда вы не доверяете профилировщику. –

Смежные вопросы