ReadToEndAsync是阻塞的,如何让它以异步方式运行?

Rj *_*aci 2 .net c# asp.net-mvc stream

我从我的控制器中的异步操作调用此getJson()函数.我有一个大文件列表,每个文件需要几秒钟才能处理ReadToEndAsync().即使我在等待它,ReadToEndAsync()也会阻塞.

如何异步调用ReadToEndAsync()?

public static async Task<T> getJson<T>(String url)
{
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(server + url);
    HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();

    String jsonString;
    //get the json string from the response
    using (var xx = response.GetResponseStream())
    {
        StreamReader reader = new StreamReader(xx, Encoding.UTF8);
        jsonString = await reader.ReadToEndAsync()
    }
}
Run Code Online (Sandbox Code Playgroud)

控制器:

_model.list.Add(await DataRetriever.getJson<ReviewModel>(url));
_model.list.Add(await DataRetriever.getJson<ReviewModel>(url));
_model.list.Add(await DataRetriever.getJson<ReviewModel>(url));
Run Code Online (Sandbox Code Playgroud)

Pet*_*iho 5

正如评论中所指出的那样,虽然该方法ReadToEndAsync()本身并不阻塞 - 通常意义上的"块"一词:也就是说,调用该方法的线程继续运行 - 它肯定会阻止代码await执行之后直到该方法已经完成.这正是您想要的:您不希望在读取完成之前执行该代码,否则将无法执行操作.

你或许应该(重?)阅读文档上asyncawait,但简要地说:关键字async应用于方法来通知它将使用的编译器await.将await用于指示所述编译器在编译器应该保存方法的当前执行状态的方法的点和返回.

如果await已经应用关键字的操作完成,框架将自动继续执行它停止的方法.在与同步上下文(例如,Winforms或WPF程序中的GUI线程)相关联的线程中调用该方法的情况下,默认情况下,该"继续"在该原始线程中执行(但在适当时可以禁用).

请注意上面的async方法从语句返回await.因此,该方法本身不会阻塞该线程,即使该方法所表示的操作在该词的某种意义上确实"阻塞".


所以,就这一切而言,在我看来,你可能正试图让你的三个操作全部异步并同时完成.如果你想这样做,你需要立即启动所有的异步操作,而不是等待每个异步操作完成,然后像现在一样继续下一步(即通过await应用于getJason<T>()方法调用的语句).

这看起来像这样:

Task<ReviewModel> task1 = DataRetriever.getJson<ReviewModel>(url1),
    task2 = DataRetriever.getJson<ReviewModel>(url2),
    task3 = DataRetriever.getJson<ReviewModel>(url3);

_model.list.Add(await task1);
_model.list.Add(await task2);
_model.list.Add(await task3);
Run Code Online (Sandbox Code Playgroud)

(注意:在您的原始代码示例中,您只使用了一个url值.由于我假设您不是真的只想在三个不同的时间执行相同的查询,我继续并更改了代码示例,以便每个任务使用不同的值).

在上文中,即使第二和/或第三任务在第一个之前完成,结果也将按顺序添加到结果列表中.但是任务本身是同时启动的,因此它们可以同时运行.


我希望上面不仅澄清了对方法的调用ReadToEndAsync()是否阻塞(它不是,虽然因为调试器执行代码的方式,它似乎确实如此),但也提供了你解决了导致你调试方法并认为它阻塞的更大问题的解决方案.即您的JSON查询未同时执行.

如果您对问题的评论和上述答案之间存在问题,请编辑您的问题,以便更准确地了解您的问题.

  • 很好的答案,但是您的描述“await”在同一线程中恢复是不正确的。只有基于 UI 的上下文才绑定到单个线程;ASP.NET 的工作方式非常不同。ASP.NET 上下文是一个“请求上下文”,因此 ASP.NET 上的“await”在另一个线程上恢复是完全有效(且常见)的,只要该“请求上下文”已移至恢复线程。 (2认同)