【发布时间】:2021-02-05 01:21:03
【问题描述】:
我最近在此处阅读了 Stephen Cleary 的帖子,内容是我们在此处以同步方法调用异步代码时可能发生的死锁:https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
关于此处稍作修改的示例(我添加的只是写行代码):
// My "library" method.
public static async Task<JObject> GetJsonAsync(Uri uri)
{
Console.WriteLine("Before await");
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(true);
return JObject.Parse(jsonString);
}
}
// My "top-level" method.
public void Button1_Click(...)
{
var jsonTask = GetJsonAsync(...);
textBox1.Text = jsonTask.Result;
}
他的解释是顶级方法阻塞了 UI 线程等待 GetJsonAsync 完成,而 GetJsonAsync 正在等待 UI 线程被释放以便它可以完成执行。
我的问题是,GetJsonAsync 不是已经在 UI 线程上吗?为什么它需要等待它被释放?根据这篇文章here,调用异步函数不一定要为要执行的方法创建另一个线程。那么如果 GetJsonAsync 一直在 UI 线程上执行,它会如何导致 UI 线程出现问题呢?就像Console.WriteLine() 执行时一样,如果不在 UI 线程上,这在哪里完成?我觉得我在这里遗漏了一些东西,但不知道是什么。
澄清:执行在什么时候离开 UI 线程/上下文并需要返回?有很多关于需要返回的讨论,但从来没有离开线程/上下文。
【问题讨论】:
-
Stephen 的解释是针对原始代码,而不是针对您修改后的示例
-
您添加了
ConfigureAwait(false),这实际上是修复的一半,而不是导致阻塞的完整代码。您正在将原始作者的结论应用于修改后的代码,同时给人以他编写的印象。两者都没有帮助。用一个新的例子可能会更好。 -
原文章很好的解释了这个问题。不知道如何改进这里
-
@MickyD 我不确定您看到的是什么,但在修改后的示例中它清楚地表示
ConfigureAwait(true),这在他编写 await 调用时暗示了这一点。我只是想更具体一点。 -
@avhhh,GetJsonAsync 在 UI 线程上执行,直到第一个
await,然后将 GetJsonAsync 的上下文保存到状态机并添加到消息循环中。消息循环将验证“每个循环”上的所有状态机,完成后会将其上下文加载到 UI 线程并继续在 UI 线程上执行。
标签: c# multithreading asynchronous async-await configureawait