当你有服务器端代码(即一些)并且你的函数是异步的 – 所以它们返回 – 是否被认为是最佳实践,任何时候你等待你调用的函数?ApiController
Task<SomeObject>
ConfigureAwait(false)
我读过它的性能更高,因为它不必将线程上下文切换回原始线程上下文。但是,对于 Web API ASP.NET,如果您的请求在一个线程上传入,并且您等待某个函数和调用,当您返回函数的最终结果时,这可能会将您置于不同的线程上。ConfigureAwait(false)
ApiController
我在下面输入了一个我正在谈论的示例:
public class CustomerController : ApiController
{
public async Task<Customer> Get(int id)
{
// you are on a particular thread here
var customer = await GetCustomerAsync(id).ConfigureAwait(false);
// now you are on a different thread! will that cause problems?
return customer;
}
}
更新:ASP.NET 核心没有 .如果您使用的是 ASP.NET Core,则是否使用并不重要。SynchronizationContext
ConfigureAwait(false)
对于 ASP.NET“完整”或“经典”或其他什么,此答案的其余部分仍然适用。
原始帖子(非核心 ASP.NET):
ASP.NET 团队的这段视频提供了有关在 ASP.NET 上使用的最佳信息。async
我读过它的性能更高,因为它不必将线程上下文切换回原始线程上下文。
对于 UI 应用程序也是如此,其中只有一个 UI 线程必须“同步”回去。
在 ASP.NET,情况要复杂一些。当方法恢复执行时,它会从 ASP.NET 线程池中获取线程。如果使用 禁用上下文捕获,则线程只会继续直接执行该方法。如果不禁用上下文捕获,则线程将重新进入请求上下文,然后继续执行该方法。async
ConfigureAwait(false)
所以不会为您节省 ASP.NET 线程跳转;它确实可以节省您重新输入请求上下文的时间,但这通常非常快。 如果您尝试对请求进行少量并行处理,可能会很有用,但实际上 TPL 更适合大多数这些场景。ConfigureAwait(false)
ConfigureAwait(false)
但是,对于 ASP.NET Web Api,如果您的请求在一个线程上传入,并且您等待某个函数并调用 ConfigureAwait(false),这可能会在返回 ApiController 函数的最终结果时将您置于不同的线程上。
实际上,只要做一个就可以做到这一点。一旦您的方法命中 ,该方法就会被阻塞,但线程会返回到线程池。当方法准备好继续时,将从线程池中抢取任何线程并用于恢复该方法。await
async
await
ASP.NET 的唯一区别是该线程在恢复方法时是否进入请求上下文。ConfigureAwait
我的 MSDN 文章和我的介绍博客文章中有更多背景信息。SynchronizationContext
async
简要回答您的问题:不。您不应该像那样在应用程序级别调用。ConfigureAwait(false)
TL;DR 版本的长答案:如果您正在编写一个不了解使用者并且不需要同步上下文的库(我认为您不应该在库中使用),则应始终使用 .否则,库的使用者可能会因以阻塞方式使用异步方法而面临死锁。这取决于情况。ConfigureAwait(false)
以下是关于方法重要性的更详细的解释(引用我的博客文章):ConfigureAwait
当您等待带有 await 关键字的方法时,编译器
会代表您生成一堆代码。此操作
的目的之一是处理与 UI(或主)线程的同步。此功能的关键
组件是
获取当前线程的同步上下文的。
根据您所在
的环境进行填充。任务的方法查找
。如果当前同步上下文不为
null,则传递给该等待者的继续将
回发到该同步上下文。SynchronizationContext.Current
SynchronizationContext.Current
GetAwaiter
SynchronizationContext.Current
当以阻塞方式使用使用新的异步语言
功能的方法时,如果您有可用的 SynchronizationContext,则
最终会出现死锁。当您以阻塞方式使用
此类方法(等待带有 Wait
方法的任务或直接从任务的
Result 属性获取结果)时,您将同时阻塞主线程。当最终任务在线程池中的该方法内完成时
,它将
调用延续以回发到主线程
,因为可用且已捕获。但是
这里有一个问题:UI 线程被阻止,你有一个
死锁!SynchronizationContext.Current
另外,这里有两篇很棒的文章,完全适合您的问题:
最后,Lucian Wischik有一个关于这个主题的精彩短视频:异步库方法应考虑使用Task.ConfigureAwait(false)。
我发现使用 ConfigureAwait(false) 的最大缺点是线程区域性恢复为系统默认值。如果您已配置区域性,例如…
<system.web>
<globalization culture="en-AU" uiCulture="en-AU" />
...
并且您托管在区域设置为 en-US 的服务器上,然后您会发现在 ConfigureAwait(false) 称为 CultureInfo.CurrentCulture 之前返回 en-AU,之后您将获得 en-US。
即
// CultureInfo.CurrentCulture ~ {en-AU}
await xxxx.ConfigureAwait(false);
// CultureInfo.CurrentCulture ~ {en-US}
如果你的应用程序正在做任何需要特定于区域性的数据格式的事情,那么在使用 ConfigureAwait(false) 时需要注意这一点。
模板简介:该模板名称为【C#对所有服务器端代码调用 ConfigureAwait 的最佳实践】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【C#】栏目查找您需要的精美模板。