任务(异步,等待):我需要输入这些都是连接层还是仅具有 ASYNC 调用的层,即 HttpClient.GetAsync?

Posted

技术标签:

【中文标题】任务(异步,等待):我需要输入这些都是连接层还是仅具有 ASYNC 调用的层,即 HttpClient.GetAsync?【英文标题】:Task(async, await): Do I need to enter these are all connecting layers or only ones with ASYNC calls i.e HttpClient.GetAsync? 【发布时间】:2013-09-19 14:13:29 【问题描述】:

我遇到了一个小问题,我写了一个asp.net web api服务,我在控制器上自动添加了“async”,当然这现在需要我使用await。

我遇到的问题是我的控制器连接到服务层,然后该服务层连接到数据层-该数据层是调用 GET 的 ASYNC 版本以对另一个 REST 进行异步调用的层服务 - 所以这很简单,我可以将我的数据层方法转换为具有“异步”关键字,然后我将等待 HttpClient GetSync 调用。

但是我的服务层支持 async / await 我需要将返回类型更改为 Task 但服务层实际上并没有做任何 ASYNC 它对实际调用 HttpClient 异步方法的数据层的调用。

所以考虑到我有以下层结构,我有 2 个选项。

ASP.NET Web API >> 服务层 >> 数据层

仅在数据层中使用 async 和 await 并完成它。

或者在控制器和服务层的方法上放置异步和等待,这需要重构,因为我需要返回任务。

我想在我不完全理解的地方,从技术上讲,唯一的阻塞调用将在数据层中,因此为了让所有线程返回线程池以供使用,我应该只关心在数据层上放置 async 和 await ?

我什么时候需要在控制器上使用模式???

期待任何帮助

【问题讨论】:

【参考方案1】:

我在控制器上自动添加了“异步”,当然这现在需要我使用等待。

那是倒退。如果需要使用await,则只应将async 添加到方法中。

仅在数据层中使用 async 和 await 并完成它。

You shouldn't wrap asynchronous methods within synchronous APIs。 尤其是在服务器代码中更是如此,因为这样你就失去了async 的所有好处。

或者在控制器和服务层的方法上放置异步和等待,这需要重构,因为我需要返回任务。

这是正确的方法。请遵循以下准则:

    不要阻止async 代码。例如,请勿致电 Task.WaitTask<T>.Result。我在我的博客how this can cause deadlocks 上进行了描述,但即使您破解它以使其可靠地工作,您仍然会失去async 在服务器端的所有好处。 避免async void。尤其是在服务器端。 请使用await,而不是WaitResult。这意味着等待方法必须是async Taskasync Task<T>,这意味着调用等待方法的方法也必须等待。所以async 将通过你的代码“成长”。这是正常且正确的。

您可能会发现我在 Best Practices in Asynchronous Programming 上的文章很有帮助。

【讨论】:

感谢 Stephen 的回复,是的,我明白不阻止任何 ASYNC 即。不使用 Result.... 我想你已经回答了我的问题,所以我将重构所有调用我的数据层的方法以使用 Task 并使用 async 和 await。这就是我担心并希望得到澄清的地方。 实际上只是想如果我只是让数据层异步并等待感知而不是别的,那么线程可以在技术上跳出(它会)并在技术上在等待之前完成程序流程方法可以返回,因此我的控制器会在它产生结果之前完成 - 这是正确的吗? - 不是我想这样做:-) @Martin:如果您尝试这样做,您会发现这是不可能的;你必须使用WaitResult之类的东西,这会阻塞请求线程。 是的...太好了...好的,我正在向链中的所有方法添加异步和等待...感谢您的帮助【参考方案2】:

如果您的调用线程没有任何有意义的事情要做,那么创建一个单独的任务来为您完成工作没有任何好处。

但是,如果调用线程有其他事情要做,例如保持 UI 响应,那么调用线程可能希望在单独的任务中调用您的函数,做其他事情,当它需要结果时等待结果.

例子:

private async YourAsyncWebFunction(...)

    // do some processing
    // call other async functions ans wait for it to finish:
    await OtherAsync(...);
    var result = await OtherAsync2(...)
    if (result == ...)  ... 


private void MyMainFunction(...)

    var taskWebFunction = Task.Run( () => YourAsyncWebFunction(...));
    // do other things
    // after a while: you need the task to finish:
    await taskWebFunction;
    // do other things
 

如果您的主函数是事件处理程序,您不必执行 Task.Run,​​只需将事件处理程序声明为异步

事件处理程序是唯一可能返回 void 而不是 Task 或 Task<TResult>

的异步函数
private async void OnButton1_Clicked(object sender, ...)

     // do some processing
     await YourAsyncWebFunction(...)

【讨论】:

以上是关于任务(异步,等待):我需要输入这些都是连接层还是仅具有 ASYNC 调用的层,即 HttpClient.GetAsync?的主要内容,如果未能解决你的问题,请参考以下文章

并行处理许多 API 请求与异步/等待 [关闭]

为啥我的循环中的异步委托没有等待

等待总是抛出 SyntaxError:等待仅在 sequelize 的异步函数中有效 [重复]

python 同步异步,并发并行,同步锁

在 iOS 中等待多个网络异步调用

执行网络调用并继续 - 异步任务