StreamWriter :(写入+刷新)异步似乎比同步变体慢

时间:2017-01-31 17:43:36

标签: c# async-await streamwriter .net-4.6.2

我试图在班上找到一个IO瓶颈,并且惊讶地注意到,当向文件写入1000000条消息时,sw.Write("m"); sw.Flush()可以比await sw.WriteAsync("m"); Await sw.FlushAsync();快20000倍。有没有人知道为什么?我的赌注是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在家用电脑上启动输出

  

在1毫秒内完成1000次迭代。

表示同步代码和

  

在43383毫秒内完成了1000次迭代。

用于异步。

更新 :我也注意到程序在FlushAsync内变慢了。 WriteAsync几乎与同步版本的速度相同。

欢迎所有评论。

更新2 * :正如@Cory Nelson在评论中提到的那样,FileStream.FlushAsync是假的async,是Task.Factory.StartNew实现的,所以它没有任何有用但有用的开销使用短消息时,与正在完成的工作相比,开销变得足够大,从而减慢了执行速度。

1 个答案:

答案 0 :(得分:5)

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);

需要注意的是,您的基准测试似乎并未捕获实际使用情况。你真的在写每个字符串并在每个字符串之后刷新吗?

Async确实有一定数量的内存和GC开销,并且具有如此短暂的操作 - 特别是当StreamWriter.WriteAsync目前没有针对小写进行优化时 - 你必然会看到比更常见的用法。