首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >等待不按预期返回调用者,使用StreamReader.ReadToEndAsync()

等待不按预期返回调用者,使用StreamReader.ReadToEndAsync()
EN

Stack Overflow用户
提问于 2017-06-13 09:34:00
回答 2查看 2.4K关注 0票数 3

试图理解流和async/await。如果我正确地理解了,await将执行返回给调用者,所以我期望下面的代码结果是:

代码语言:javascript
运行
复制
before calling async ReadToEnd
after the call to ReadToEnd
before calling async ReadToEnd
after the call to ReadToEnd

但它确实是

代码语言:javascript
运行
复制
before calling async ReadToEnd
after the call to ReadToEnd
before calling async ReadToEnd
after await in ReadToEnd. streamReader.BaseStream.GetType(): System.IO.MemoryStream
after the call to ReadToEnd

在调用StreamReader时,使用带有FileStreamStreamReader.ReadToEndAsync()似乎确实会返回给调用方,但是当使用下面有MemoryStreamStreamReader时,它就不能工作了。

为了理解正在发生的事情,我阅读了.NET源代码,并得出了这样的结论:用下面的MemoryStream调用StreamReader.ReadToEndAsync()最终会调用BaseStream上的ReadAsync() (来源)。对于MemoryStreamReadAsync()实际上不是异步方法,因此不会返回给调用者。

我的理解正确吗?

代码语言:javascript
运行
复制
using System;
using System.Text;
using System.Linq;
using System.IO;
using System.Threading.Tasks;

static class Program
{
    public static void Main(string[] args)
    {
        var longString = new string(Enumerable.Repeat('x', 100000000).ToArray());
        File.WriteAllText("bigFile.txt", longString, Encoding.UTF32);

        StreamReader fileStreamReader = new StreamReader(File.OpenRead(@"bigFile.txt"));
        Console.WriteLine("before calling async ReadToEnd");
        var task = ReadToEnd(fileStreamReader);
        Console.WriteLine("after the call to ReadToEnd");

        byte[] bytes = Encoding.UTF32.GetBytes(longString);
        StreamReader memoryStreamReader = new StreamReader(new MemoryStream(bytes));
        Console.WriteLine("before calling async ReadToEnd");
        var task2 = ReadToEnd(memoryStreamReader);
        Console.WriteLine("after the call to ReadToEnd");

        fileStreamReader.Dispose();
        memoryStreamReader.Dispose();
    }

    static async Task ReadToEnd(StreamReader streamReader)
    {
        string allText = await streamReader.ReadToEndAsync();
        Console.WriteLine("after await in ReadToEnd. streamReader.BaseStream.GetType(): " + streamReader.BaseStream.GetType());
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-06-13 09:53:11

只有在等待的事情没有同步完成时,await才会将执行返回给调用方。是的,如果async方法选择,它们可以同步完成,原因之一是:

  • 他们已经知道了答案(缓存的结果、缓冲的数据、已知的故障状态等)。
  • 它们根本没有合适的异步下游操作来执行。

MemoryStream总是同步的,所以它总是这样做的。

相反,FileStream可能同步完成,也可能不同步完成,这取决于缓冲区中可用的数据,等等。

是否返回调用方的决定是由GetAwaiter().IsCompleted驱动的,它(对于Task)可以归结为.IsCompleted

票数 8
EN

Stack Overflow用户

发布于 2017-06-13 09:53:03

在代码的第一部分中,您将从StreamReader创建File。当您调用streamReader.ReadToEndAsync()时,必须先将文件读入硬盘驱动器的内存中,然后才能返回内容,这是异步完成的。

在代码的第二部分中,您将从MemoryStream创建MemoryStream,它是从已经加载到应用程序内存中的bytes构建的。在这种情况下,streamReader.ReadToEndAsync()会立即返回内容,因为数据在内存中,可以立即获取。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44517607

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档