为什么 ThreadPool 决定使用调用 Task.Wait 的确切上下文线程?

Why ThreadPool decides to use the exact context thread which called Task.Wait?

为什么 ThreadPool 决定使用调用 Task.Wait 的确切上下文线程?

the question。由于某些原因,我没有看到问题及其任何答案的评论按钮。所以,我在一个单独的线程中问一个相关的问题。

在链接的问题中有一个指向 the blog 的答案。根据此博客,以下声明成立。

有代码块:

// My "library" method.
public static async Task<JObject> GetJsonAsync(Uri uri)
{
  // (real-world code shouldn't use HttpClient in a using block; this is just example code)
  using (var client = new HttpClient())
  {
    var jsonString = await client.GetStringAsync(uri);
    return JObject.Parse(jsonString);
  }
}

// My "top-level" method.
public void Button1_Click(...)
{
  var jsonTask = GetJsonAsync(...);
  textBox1.Text = jsonTask.Result;
}

还有死锁发生的解释:

  1. The top-level method calls GetJsonAsync (within the UI/ASP.NET context).
  2. GetJsonAsync starts the REST request by calling HttpClient.GetStringAsync (still within the context).
  3. GetStringAsync returns an uncompleted Task, indicating the REST request is not complete.
  4. GetJsonAsync awaits the Task returned by GetStringAsync. The context is captured and will be used to continue running the GetJsonAsync method later. GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete.
  5. The top-level method synchronously blocks on the Task returned by GetJsonAsync. This blocks the context thread.
  6. … Eventually, the REST request will complete. This completes the Task that was returned by GetStringAsync.
  7. The continuation for GetJsonAsync is now ready to run, and it waits for the context to be available so it can execute in the context.
  8. Deadlock. The top-level method is blocking the context thread, waiting for GetJsonAsync to complete, and GetJsonAsync is waiting for the context to be free so it can complete.

我的问题特别是关于第 7 步。为什么 ThreadPool 决定使用一个阻塞的线程并等待它解除阻塞以请求该线程 运行 代码?为什么不直接使用其他线程?

GetJsonAsync不在任意线程池线程上执行。它在上下文线程上执行。

根据示例代码,任务 GetJsonAsync 由按钮单击事件创建,该事件在 UI 线程(上下文线程)上执行。等待任务时,捕获当前上下文(在本例中为 UI 同步上下文)。任务完成后,继续在同一上下文中恢复。

第7步,任务试图return到UI线程,但是UI线程被.Result阻塞,等待任务return。所以死锁发生了。

我注意到引用的问题是询问 ASP.NET WebApi 应用程序。所以只想澄清几点:

ASP.Net WebAPI 确实有一个特殊的同步上下文,但它不同于UI 上下文。只有一个 UI 线程,因此上下文仅将回调/延续安排到 UI 线程。

但是,ASP.Net WebAPI 的同步上下文不会捕获一个线程。 ASP.Net 代码可以在不同/任意线程上 运行。上下文负责恢复线程数据并确保延续以先到先得的方式链接在一起。