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

vto*_*ola 3 .net streamwriter async-await

我正在创建一个类继承自的类Stream.当我使用StreamWriter类异步写入信息时:

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
    await sw.WriteAsync(msg);
Run Code Online (Sandbox Code Playgroud)

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

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

vto*_*ola 7

我发现了混乱的根源.

StreamWriter 默认情况下会同步刷新,除非您专门异步刷新.

Stream.Flush 关闭时调用,当然还有冲洗.

这将调用Write而不是WriteAsyncmessageWriter流中:

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
    await sw.WriteAsync("Hi");
Run Code Online (Sandbox Code Playgroud)

StreamWriter将缓冲"Hi"的消息,并且其将被释放到底层流上Flush关闭时同步地调用StreamWriter.

因此,异步调用StreamWriter.WriteAsync可能对底层流没有影响(因为缓冲),并且在调用时StreamWriter.Close,StreamWriter.Flush会同步调用,因此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 
}
Run Code Online (Sandbox Code Playgroud)

显然这也是这个:

using (var sw = new StreamWriter(messageWriter, Encoding.UTF8))
{
    await sw.WriteAsync("Hi"); 
    sw.Flush(); 
}
Run Code Online (Sandbox Code Playgroud)

这会打电话WriteAsync:

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

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

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

而这个测试:

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

产量:

Simple
Write
Write

AutoFlush
Write
WriteAsync

Flush async
WriteAsync
WriteAsync
Run Code Online (Sandbox Code Playgroud)

第一个写入是UTF8 BOM,第二个是实际数据.