StreamWriter:(Write+Flush)Async 似乎比同步变体慢得多

StreamWriter: (Write+Flush)Async seem much slower then synchronous variants

我试图在我的 class 中找到一个 IO 瓶颈,并且惊奇地注意到 sw.Write("m"); sw.Flush() 可以比 await sw.WriteAsync("m"); Await sw.FlushAsync(); 快 20000,当将 1000000 条消息写入一个文件时。有没有人知道为什么?我敢打赌 StreamWriter 的构造函数采用 String 不会为 async 用法参数化流。

下面的代码可以从 C# interactive 启动。是的,这不是测量速度的最佳位置,但无论如何它都会显示手边的问题:

var sr = new StreamWriter("G:\file.file");
var N = 1000;
var sw = new Stopwatch();
sw.Start();

for (var i = 0; i < N; ++i)
{
    sr.Write("m"); // or await sr.WriteAsync("m");
    sr.Flush(); // or await sr.FlushAsync("m");
}

sw.Stop();
Console.WriteLine("Completed " + N
    + " iterations in " + sw.ElapsedMilliseconds + " milliseconds.");

sr.Close();

从 C# Interactive 在我的家用 PC 上启动,输出是

Completed 1000 iterations in 1 milliseconds.

用于同步代码和

Completed 1000 iterations in 43383 milliseconds.

对于异步。

Update:我还注意到程序在 FlushAsync 中变慢了。 WriteAsync 工作速度几乎与同步版本相同。

欢迎所有评论。

更新 2*:正如@Cory Nelson 在对他的回答的评论中提到的,FileStream.FlushAsync 是用 [=20 实现的假 async =],所以除了开销之外,它没有增加任何有用的东西。当处理短消息时,与正在完成的工作相比,开销变得足够大,从而减慢了执行速度。

StreamWriter,当给定文件路径时,不会以异步模式打开其基础流。这可能会导致性能损失。如果你打算将它用于异步,你应该打开你自己的 Stream:

Stream s = new FileStream("G:\file.file", FileMode.Create, FileAccess.Write,
                          FileShare.None, 4096,
                          FileOptions.Asynchronous | FileOptions.SequentialScan);
StreamWriter sr = new StreamWriter(s);

另外需要注意的是,您的基准测试似乎没有捕获 real-world 使用情况。你真的在写 single-character 个字符串并在每个字符串后刷新吗?

Async 确实有一定数量的内存和 GC 开销,并且有这样的 short-lived 操作——特别是因为 StreamWriter.WriteAsync 目前没有针对小写操作进行优化——你一定会看到比更常见的用法更多的开销。