本文翻译自:Best practice to call ConfigureAwait for all server-side code

When you have server-side code (ie some ApiController ) and your functions are asynchronous - so they return Task<SomeObject> - is it considered best practice that any time you await functions that you call ConfigureAwait(false) ? 当你有服务器端代码(即一些ApiController )并且你的函数是异步的 - 所以它们返回Task<SomeObject> - 你认为最好的做法是等待你调用ConfigureAwait(false)函数吗?

I had read that it is more performant since it doesn't have to switch thread contexts back to the original thread context. 我已经读过它更高效,因为它不必将线程上下文切换回原始线程上下文。 However, with ASP.NET Web Api, if your request is coming in on one thread, and you await some function and call ConfigureAwait(false) that could potentially put you on a different thread when you are returning the final result of your ApiController function. 但是,使用ASP.NET Web Api,如果您的请求是在一个线程上进行的,并且等待某个函数并调用ConfigureAwait(false) ,当您返回ApiController函数的最终结果时,它可能会将您置于不同的线程上。

I've typed up an example of what I am talking about below: 我在下面输入了一个我正在谈论的例子:

public class CustomerController : ApiController
{public async Task<Customer> Get(int id){// you are on a particular thread herevar customer = await SomeAsyncFunctionThatGetsCustomer(id).ConfigureAwait(false);// now you are on a different thread!  will that cause problems?return customer;}
}

#1楼

参考:https://stackoom.com/question/ub7Z/为所有服务器端代码调用ConfigureAwait的最佳实践


#2楼

Brief answer to your question: No. You shouldn't call ConfigureAwait(false) at the application level like that. 您的问题的简要回答:不。您不应该在应用程序级别调用ConfigureAwait(false)

TL;DR version of the long answer: If you are writing a library where you don't know your consumer and don't need a synchronization context (which you shouldn't in a library I believe), you should always use ConfigureAwait(false) . TL;答案的DR版本:如果你正在编写一个你不了解你的消费者并且不需要同步上下文的库(你不应该在我认为的库中),你应该总是使用ConfigureAwait(false) Otherwise, the consumers of your library may face deadlocks by consuming your asynchronous methods in a blocking fashion. 否则,您的库的使用者可能会以阻塞方式使用异步方法而面临死锁。 This depends on the situation. 这取决于具体情况。

Here is a bit more detailed explanation on the importance of ConfigureAwait method (a quote from my blog post): 以下是有关ConfigureAwait方法重要性的更详细解释(来自我的博客文章):

When you are awaiting on a method with await keyword, compiler generates bunch of code in behalf of you. 当您在等待具有await关键字的方法时,编译器会代表您生成大量代码。 One of the purposes of this action is to handle synchronization with the UI (or main) thread. 此操作的目的之一是处理与UI(或主)线程的同步。 The key component of this feature is the SynchronizationContext.Current which gets the synchronization context for the current thread. 此功能的关键组件是SynchronizationContext.Current ,它获取当前线程的同步上下文。 SynchronizationContext.Current is populated depending on the environment you are in. The GetAwaiter method of Task looks up for SynchronizationContext.Current . 根据您所处的环境填充SynchronizationContext.CurrentGetAwaiter方法将查找SynchronizationContext.Current If current synchronization context is not null, the continuation that gets passed to that awaiter will get posted back to that synchronization context. 如果当前同步上下文不为null,则传递给该awaiter的延续将返回到该同步上下文。

When consuming a method, which uses the new asynchronous language features, in a blocking fashion, you will end up with a deadlock if you have an available SynchronizationContext. 当使用阻塞方式使用新异步语言功能的方法时,如果您有可用的SynchronizationContext,则最终会出现死锁。 When you are consuming such methods in a blocking fashion (waiting on the Task with Wait method or taking the result directly from the Result property of the Task), you will block the main thread at the same time. 当您以阻塞方式使用此类方法(等待Task with Wait方法或直接从Task的Result属性获取结果)时,您将同时阻止主线程。 When eventually the Task completes inside that method in the threadpool, it is going to invoke the continuation to post back to the main thread because SynchronizationContext.Current is available and captured. 当最终任务在线程池中的该方法内完成时,它将调用continuation以回发到主线程,因为SynchronizationContext.Current可用并被捕获。 But there is a problem here: the UI thread is blocked and you have a deadlock! 但这里有一个问题:UI线程被阻止,你有一个死锁!

Also, here are two great articles for you which are exactly for your question: 另外,这里有两篇很棒的文章,完全适合您的问题:

  • The Perfect Recipe to Shoot Yourself in The Foot - Ending up with a Deadlock Using the C# 5.0 Asynchronous Language Features 使用C#5.0异步语言功能在脚中完成自我拍摄的完美配方
  • Asynchronous .NET Client Libraries for Your HTTP API and Awareness of async/await's Bad Effects 用于HTTP API的异步.NET客户端库和async / await的恶意效果

Finally, there is a great short video from Lucian Wischik exactly on this topic: Async library methods should consider using Task.ConfigureAwait(false) . 最后, Lucian Wischik有一个关于这个主题的精彩视频: 异步库方法应该考虑使用Task.ConfigureAwait(false) 。

Hope this helps. 希望这可以帮助。


#3楼

I have some general thoughts about the implementation of Task : 我对Task的实现有一些一般性的想法:

  1. Task is disposable yet we are not supposed to use using . 任务是一次性的,但我们不应该 using
  2. ConfigureAwait was introduced in 4.5. ConfigureAwait是在4.5中引入的。 Task was introduced in 4.0. Task在4.0中引入。
  3. .NET Threads always used to flow the context (see C# via CLR book) but in the default implementation of Task.ContinueWith they do not b/c it was realised context switch is expensive and it is turned off by default. .NET Threads 总是用于流动上下文(请参阅C#通过CLR书),但在Task.ContinueWith的默认实现中,他们没有b / c它实现了上下文切换是昂贵的,并且它默认关闭。
  4. The problem is a library developer should not care whether its clients need context flow or not hence it should not decide whether flow the context or not. 问题是库开发人员不应该关心它的客户端是否需要上下文流,因此它不应该决定是否流动上下文。
  5. [Added later] The fact that there is no authoritative answer and proper reference and we keep fighting on this means someone has not done their job right. [后来补充]事实上没有权威的答案和适当的参考,我们继续争取这意味着有人没有完成他们的工作。

I have got a few posts on the subject but my take - in addition to Tugberk's nice answer - is that you should turn all APIs asynchronous and ideally flow the context . 我有一些关于这个主题的帖子 ,但除了Tugberk的好答案之外,我还有一个问题就是你应该把所有API变成异步并理想地流动上下文。 Since you are doing async, you can simply use continuations instead of waiting so no deadlock will be cause since no wait is done in the library and you keep the flowing so the context is preserved (such as HttpContext). 由于您正在执行异步操作,因此您可以简单地使用continuation而不是等待,因此不会导致死锁,因为在库中没有等待并且您保持流动以便保留上下文(例如HttpContext)。

Problem is when a library exposes a synchronous API but uses another asynchronous API - hence you need to use Wait() / Result in your code. 问题是当库公开同步API但使用另一个异步API时 - 因此您需要在代码中使用Wait() / Result


#4楼

Update: ASP.NET Core does not have a SynchronizationContext . 更新: ASP.NET Core没有SynchronizationContext If you are on ASP.NET Core, it does not matter whether you use ConfigureAwait(false) or not. 如果您使用的是ASP.NET Core,则无论是否使用ConfigureAwait(false)无关紧要。

For ASP.NET "Full" or "Classic" or whatever, the rest of this answer still applies. 对于ASP.NET“Full”或“Classic”等等,本答案的其余部分仍然适用。

Original post (for non-Core ASP.NET): 原帖(非核心ASP.NET):

This video by the ASP.NET team has the best information on using async on ASP.NET. ASP.NET团队的这段视频提供了有关在ASP.NET上使用async的最佳信息。

I had read that it is more performant since it doesn't have to switch thread contexts back to the original thread context. 我已经读过它更高效,因为它不必将线程上下文切换回原始线程上下文。

This is true with UI applications, where there is only one UI thread that you have to "sync" back to. UI应用程序也是如此,其中只有一个UI线程需要“同步”回来。

In ASP.NET, the situation is a bit more complex. 在ASP.NET中,情况有点复杂。 When an async method resumes execution, it grabs a thread from the ASP.NET thread pool. async方法恢复执行时,它会从ASP.NET线程池中获取一个线程。 If you disable the context capture using ConfigureAwait(false) , then the thread just continues executing the method directly. 如果使用ConfigureAwait(false)禁用上下文捕获,则线程将继续直接执行该方法。 If you do not disable the context capture, then the thread will re-enter the request context and then continue to execute the method. 如果不禁用上下文捕获,则线程将重新进入请求上下文,然后继续执行该方法。

So ConfigureAwait(false) does not save you a thread jump in ASP.NET; 因此, ConfigureAwait(false)不会在ASP.NET中保存线程跳转; it does save you the re-entering of the request context, but this is normally very fast. 它确实可以帮助您重新输入请求上下文,但这通常非常快。 ConfigureAwait(false) could be useful if you're trying to do a small amount of parallel processing of a request, but really TPL is a better fit for most of those scenarios. 如果您尝试对请求执行少量并行处理,则ConfigureAwait(false) 可能很有用,但实际上TPL更适合大多数情况。

However, with ASP.NET Web Api, if your request is coming in on one thread, and you await some function and call ConfigureAwait(false) that could potentially put you on a different thread when you are returning the final result of your ApiController function. 但是,使用ASP.NET Web Api,如果您的请求是在一个线程上进行的,并且等待某个函数并调用ConfigureAwait(false),当您返回ApiController函数的最终结果时,它可能会将您置于不同的线程上。

Actually, just doing an await can do that. 实际上,只是做一个await可以做到这一点。 Once your async method hits an await , the method is blocked but the thread returns to the thread pool. 一旦您的async方法命中await ,该方法就会被阻止,但该线程会返回到线程池。 When the method is ready to continue, any thread is snatched from the thread pool and used to resume the method. 当方法准备好继续时,从线程池中抢夺任何线程并用于恢复该方法。

The only difference ConfigureAwait makes in ASP.NET is whether that thread enters the request context when resuming the method. ConfigureAwait在ASP.NET中唯一的区别是该线程在恢复方法时是否进入请求上下文。

I have more background information in my MSDN article on SynchronizationContext and my async intro blog post . 我在关于SynchronizationContext MSDN文章和我的async介绍博客 文章中有更多背景信息。


#5楼

The biggest draw back I've found with using ConfigureAwait(false) is that the thread culture is reverted to the system default. 我在使用ConfigureAwait(false)时发现的最大缺点是线程文化被恢复为系统默认值。 If you've configured a culture eg ... 如果您已经配置了文化,例如......

<system.web><globalization culture="en-AU" uiCulture="en-AU" />    ...

and you're hosting on a server whose culture is set to en-US, then you will find before ConfigureAwait(false) is called CultureInfo.CurrentCulture will return en-AU and after you will get en-US. 并且您将托管在其文化设置为en-US的服务器上,然后您将在ConfigureAwait(false)之前找到CultureInfo.CurrentCulture将返回en-AU并在您获得en-US之后。 ie

// CultureInfo.CurrentCulture ~ {en-AU}
await xxxx.ConfigureAwait(false);
// CultureInfo.CurrentCulture ~ {en-US}

If your application is doing anything which requires culture specific formatting of data, then you'll need to be mindful of this when using ConfigureAwait(false). 如果您的应用程序正在执行任何需要特定于文化的数据格式化的操作,那么在使用ConfigureAwait(false)时您需要注意这一点。

为所有服务器端代码调用ConfigureAwait的最佳实践相关推荐

  1. 编写超级可读代码的15个最佳实践

    一月两次,我们重温Nettuts历史上读者最喜欢的文章. 代码可读性是一个计算机编程世界的普遍主题.它是我们作为开发者第一件学习的事情.这篇文章将阐述编写可读性代码十五个最重要的最佳实践. ----- ...

  2. .NET Core调用WCF的最佳实践

    现在.NET Core貌似很火,与其他.NET开发者交流不说上几句.NET Core都感觉自己落伍了一样.但是冷静背后我们要也看到.NET Core目前还有太多不足,别的不多说,与自家的服务框架WCF ...

  3. 修改软件的艺术:构建易维护代码的9条最佳实践

    内容简介 遗留代码就是指因为种种原因格外难以修正.改进以及使用的代码,这样的代码有很多,每天我们都会因为遗留代码而损失时间.金钱和机遇,软件产业通常轻视可维护性,所以到最后企业花在维护代码上的成本比一 ...

  4. 代码阅读方法与最佳实践

    引言 阅读代码是程序员的基本技能,同时也是软件开发.维护.演进.审查和重用过程中不可或缺的组成部分.本文首次将阅读代码作为一项独立课题,系统性地加以论述.开放源码项目-是所有程序员都应该珍视的宝库. ...

  5. 使用leaflet或者openlayers 3 调用MapServer服务最佳实践完整说明

    本文系转载,原文链接: https://blog.csdn.net/future_todo/article/details/71187031 最近尝试了很多次,看到网上的很多教程都是版本比较老旧,会出 ...

  6. [Client]前端代码规范 及 最佳实践

    前端代码规范 及 最佳实践 2014/10/29 | 分类: WEB前端, 工具与资源, 开发 | 0 条评论 | 标签: 代码规范, 前端开发, 最佳实践 分享到: 62 本文作者: 伯乐在线 -  ...

  7. [转载]前端代码规范 及 最佳实践

    http://blog.jobbole.com/79075/#_general_practices 本文作者: 伯乐在线 - 老码农 .未经许可,禁止转载! 欢迎分享原创到伯乐头条. 本文来自 Iso ...

  8. 前端代码规范及最佳实践

    本文来自 Isobar公司 的 github repo 中文版 翻译: @老码农的自留地 概述 本文档包含了Isobar公司的创意技术部(前端工程)开发web应用的规范.现在我们把它开放给任何希望了解 ...

  9. 前端代码规范 及 最佳实践

    本文来自 Isobar公司 的 github repo 中文版 翻译: @老码农的自留地 概述 本文档包含了Isobar公司的创意技术部(前端工程)开发web应用的规范.现在我们把它开放给任何希望了解 ...

最新文章

  1. 图片上两点之间的距离和两组图片之间的差异的关系
  2. Eclipse将整个项目的HTML文件编码改为UTF-8
  3. 解决“跨域问题”的几种方法
  4. java技术难点_Java核心技术第四章----对象与类重难点总结
  5. 学php要先学css吗,学PHP是不是就必须学htmlcssjs
  6. ssms排序代码_SSMS中的代码片段概述
  7. I.MX6 android 4.2 源码下载
  8. Qt反射内存读取大文件
  9. 【Android开发】图形图像处理技术-绘制文本
  10. pythonlocust使用技巧_python locust 性能测试:HOOKS钩子方法
  11. 虚拟机上安装openwrt并开发ipk包
  12. vmoptions默认配置_VM options 以及 properties文件的一些理解
  13. VScode窗口保持
  14. 用手机写一个抓cookie软件
  15. 文章结构层次序数(序号)的规范要求
  16. 三菱FX5U系列PLC内置模拟量使用方法和输入输出信号接线
  17. 如何应对大数据分析工程师面试Spark考察,看这一篇就够了
  18. 1、STM32开发-环境搭建-Keil5安装
  19. android代码修改mp3文件封面,从android中的mp3文件中提取专辑封面
  20. NAT ,BFD ,NQA 实验

热门文章

  1. 垃圾回收器机制(一):对象存活及强,弱等各种引用辨析
  2. [置顶] 自己动手实现OpenGL-OpenGL原来如此简单(二)
  3. 总结一下这几天操作符的学习心得
  4. 关于WSE_CLIPSIBLINGS
  5. 关于openGL学习心得
  6. 解决: is not accessible from java.lang.Class android.app.AppComponentFactory
  7. Android toolbar menu 字体点击样式
  8. 【网络】HTTP基础总结
  9. 【Android】安卓布局文件中xmlns属性
  10. docker ubuntu镜像_docker使用教程