如您所知,在等待不需要捕获同步上下文的代码中的任务时调用Task.ConfigureAwait(false)
是个好主意,因为否则它可以cause deadlocks。 / p>
那么,您需要多久捕获一次同步上下文?我的练习,很少。在大多数情况下,我正在使用“库”代码,这几乎迫使我一直使用Task.ConfigureAwait(false)
。
所以我的问题非常简单:为什么Task.ConfigureAwait(false)
不是任务的默认选项?强制“高级”代码使用Task.ConfigureAwait(true)
不是更好吗?这有历史原因,还是我错过了什么?
答案 0 :(得分:14)
与.ConfigureAwait(false)
一起使用的大多数代码也可以使用.ConfigureAwait(true)
,但效果不理想。是的,不是所有代码,但仍然是最多的。当前默认设置允许最高百分比的代码工作,而无需修改典型程序员遗憾无法理解的设置。
一个不同的默认值只会导致成千上万的关于代码无法运行的问题,更糟糕的是,成千上万的答案以微软的形式糟透了,他们让你在每个人写Control.CheckForIllegalCrossThreadCalls = false;
程序。为什么不是默认的?"而不是实际添加适当的.ConfigureAwait(true)
电话。
答案 1 :(得分:9)
仅仅因为你的典型用例需要ConfigureAwait(false),它并不意味着它是"正确的"或最常用的选项。
async / await的设计之一就是编写响应式GUI程序。在这种情况下,在将一些工作卸载到Task之后返回UI线程是至关重要的,因为UI更新只能从大多数Windows GUI平台上的主线程发生。 Async / await帮助GUI开发人员做正确的事情。
这不是默认选项更有意义的唯一示例。我只能推测,但我怀疑对ConfigureAwait默认的决定是基于确保异步对尽可能少的摩擦起作用,对于Microsoft预期它将被最多使用的用例。不是每个人都在编写框架。
答案 2 :(得分:8)
从该链接查看第二个示例解决方案:
public async void Button1_Click(...)
{
var json = await GetJsonAsync(...);
textBox1.Text = json;
}
public class MyController : ApiController
{
public async Task<string> Get()
{
var json = await GetJsonAsync(...);
return json.ToString();
}
}
如果默认行为是ConfigureAwait(false)
,则textBox1.Text = json;
语句将在随机线程池线程而不是UI线程上执行。
两个片段看起来都像某人可以合理写的代码,默认情况下,其中一个片段必须被破坏。由于死锁比线程不安全的访问危险性更小且更易于检测,因此选择ConfigureAwait(true)
作为默认选择是更保守的选择。