为什么.NET异步等待文件副本比同步File.Copy()调用消耗更多的CPU?

Eho*_*ret 7 .net c# io asynchronous file-copying

为什么下面的代码导致:

.NET异步文件副本

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");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

而File.Copy():https://msdn.microsoft.com/en-us/library/system.io.file.copy( v= vs.110).aspx 消耗的cpu要少得多:

同步文件复制

因此,使用async/await进行文件复制仍然存在真正的兴趣吗?

我认为保存一个复制线程可能是值得的,但File.Copy windows函数似乎在CPU%方面赢得了战斗.有些人认为这是因为真正的DMA支持,但我仍然在做什么来破坏性能?或者有什么可以通过我的异步方法来提高CPU使用率?

Han*_*ant 8

这些是非常荒谬的性能数字.你根本就没有衡量自己的想法.这不应该只是一个小的blip,一个简单的内存到内存副本的缓存文件数据.像File.Copy()一样.在具有不错的DDR3 RAM的机器上以约35千兆字节/秒的速度运行,因此不能超过几十毫秒.即使文件没有被缓存或者机器没有足够的RAM,你仍然无法获得这种CPU负载,你的代码将被阻塞等待磁盘.

实际看到的是已安装的反恶意软件产品的性能.当它看到程序操纵可执行文件时,它总是将它的内衣捆绑在一起.

简单验证,禁用或排除,然后重试.

  • “您实际看到的是您安装的反恶意软件产品的性能。” ——你能澄清一下你在这里的意思吗?你是说反恶意软件产品使用了一堆显示在 Visual Studio 中的 CPU?或者你是说另一个程序导致@EhouarnPerret 的程序本身使用更多的 CPU?我刚刚打开 Prime95,它在任务管理器中将我的所有 8 个内核都固定为 100%,但 Visual Studio 仍然显示 ~13% 的 CPU 使用率,与任务管理器为我的 1 个“控制台应用程序”进程显示的数量相同。 (2认同)
  • 您通常不会看到反恶意软件引起的开销,因为您没有探测器观察程序正在做什么的奢侈.不要拍摄信使:)如果您有另一个不信任分析器的情况,请单击"提问"按钮. (2认同)

Jon*_*nna 5

File.OpenRead(sourceFileName)相当于对于异步I/O而言new FileStream(sourceFileName,?FileMode.Open,?FileAccess.Read,?FileShare.Read)等效于public FileStream(sourceFileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, false)哪一个false.等效的是File.OpenWrite.

因此,任何XXXAsync操作都不会使用异步I/O,但会使用线程池线程伪造它.

因此它不会产生异步I/O的好处,并且浪费至少一个线程.您在I/O上有一个额外的线程阻塞,这是您想要避免的.我一般都希望异步本身比同步执行稍慢(异步通常会牺牲一次性速度以获得更好的可伸缩性)但是我绝对希望这样做可以做得更好,如果有的话,而不是包装整个内容Task.Run().

我仍然没有想到它会如此糟糕,但也许反恶意软件正在写入.exe.

你希望能更好地复制非exe和异步流.

  • 异步复制比同步慢几倍,我不会感到震惊.当我想要更高的单操作吞吐量时,我不会使用它; 当我想在其他时间做其他事情时,我会使用它,或者当我不关心我服务单个请求的速度时,我会使用它,就像我快速服务一样很多,我可以同时服务多少. (2认同)