StreamWriter在调用异步方法时使用同步调用

时间:2014-02-24 12:17:26

标签: async-await streamwriter .net

我正在创建类似于类的流,它继承自Stream。当我使用StreamWriter类异步写入信息时:

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
    await sw.WriteAsync(msg);

我可以看到StreamWriter直接转到void Stream.Write(byte[] buffer, int offset, int count)而不是Task Stream.WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)

这是一个错误还是我错过了什么?

2 个答案:

答案 0 :(得分:7)

我发现了混乱的根源。

除非您专门异步刷新,否则

StreamWriter默认情况下会同步刷新。

关闭时会调用

Stream.Flush,当然还会刷新。

这将在Write信息流中调用WriteAsync而不是messageWriter

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
    await sw.WriteAsync("Hi");

StreamWriter将缓冲“Hi”消息,并在关闭Flush时同步释放到StreamWriter调用的基础流。

因此对StreamWriter.WriteAsync的异步调用可能对底层流没有影响(因为缓冲),并且在调用StreamWriter.Close时,同步调用StreamWriter.Flush,因此{{ 1}}基础流上的方法。

此代码也同步调用Flush

Write

显然也是这个:

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
{
    sw.AutoFlush = true; // will call Write here to send the UTF8 BOM
    await sw.WriteAsync("Hi"); // Write the actual data 
}

这将调用using (var sw = new StreamWriter(messageWriter, Encoding.UTF8)) { await sw.WriteAsync("Hi"); sw.Flush(); }

WriteAsync

我创建了一个简单的类来跟踪方法的调用方式:

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
{
    await sw.WriteAsync("Hi");
    await sw.FlushAsync()
}

这个测试:

public class MSWrite : MemoryStream
{
    public override bool CanWrite { get { return true; } }

    public override void Write(byte[] buffer, int offset, int count)
    {
        Console.WriteLine("Write");
    }

    public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
    {
        Console.WriteLine("WriteAsync");
        return Task.Run(() => { });
    }
}

收率:

Console.WriteLine("Simple");
using(var ms = new MSWrite())
using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
{
    await sw.WriteAsync("Hi");
}
Console.WriteLine();

Console.WriteLine("AutoFlush");
using (var ms = new MSWrite())
using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
{
    sw.AutoFlush = true;
    await sw.WriteAsync("Hi");
}
Console.WriteLine();

Console.WriteLine("Flush async");
using (var ms = new MSWrite())
using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
{
    await sw.WriteAsync("Hi");
    await sw.FlushAsync();
}

第一次写入是UTF8 BOM,第二次是实际数据。

答案 1 :(得分:2)

不,StreamWriter.WriteAsync实际上会调用Stream.WriteAsync(假设您使用的是.NET 4.5)。如果您没有看到,请发布堆栈跟踪。

请注意,默认情况下,Stream基类将在线程池线程上实现WriteAsync Write。您需要在自定义流中覆盖WriteAsync才能更改此行为。