等待和僵局预防 - 澄清?

Roy*_*mir 6 .net c# task-parallel-library async-await

我读了这篇文章,了解Task.ConfigureAwait哪些可以帮助防止异步代码中的死锁.

看看这段代码:( 我知道我不应该这样做.Result,但这是问题的一部分)

private void Button_Click(object sender, RoutedEventArgs e)
{
    string result = GetPageStatus().Result;
    Textbox.Text = result;
}
public async Task<string> GetPageStatus()
{
    using (var httpClient = new HttpClient())
    {
        var response = await httpClient.GetAsync("http://www.google.com");
        return response.StatusCode.ToString();
    }
}
Run Code Online (Sandbox Code Playgroud)

这将导致死锁,因为:

  1. 然后.Result- 操作将在等待异步操作完成时阻止当前线程(即UI线程).

  2. 一旦网络调用完成,它将尝试继续response.StatusCode.ToString()在捕获的上下文上执行- 方法.(被封锁 - 因此死锁).

一种解决方案是使用:

var response = await httpClient.GetAsync("http://www.google.com").ConfigureAwait(false);

但其他解决方案是一直异步(没有阻塞):

/*1*/   private async void Button_Click(object sender, RoutedEventArgs e)
/*2*/   {
/*3*/       string result = await GetPageStatus();
/*4*/       Textbox.Text = result;
/*5*/   }
/*6*/   public async Task<string> GetPageStatus()
/*7*/   {
/*8*/       using (var httpClient = new HttpClient())
/*9*/       {
/*10*/          var response = await httpClient.GetAsync("http://www.google.com");
/*11*/          return response.StatusCode.ToString();
/*12*/      }
/*13*/   }
Run Code Online (Sandbox Code Playgroud)

题 :

(我试图了解这段代码如何帮助解决问题 - 通过上下文POV).

  1. 线#3和线是否#10捕获不同的上下文?

  2. 关于流动的方式,我认为是正确的:

    • 第3行调用#6(调用#10)并看到它还没有完成,所以它等待(#3 = UI线程的捕获上下文).

    • 稍后,第10行在完成后捕获另一个上下文(我将其称为newContext),它返回"newContext"然后释放UI上下文(线程).

我是对的吗?

  1. 可视化:(这是正确的流程吗?)

代码执行流程

i3a*_*non 3

没有不同的上下文。在这两种情况下,SyncrhonizationContext都是单线程 UI 同步上下文(只要您不使用ConfigureAwait(false)

\n\n

当 UI 线程同步等待自身时,就会发生死锁。您可以通过避免 UI 线程ConfigureAwait(false)或不阻止它来解决这个问题Task.Result

\n\n

async一路走下去”解决死锁的原因是UI线程不再被阻塞并且可以自由地运行两者的延续\xd7\x93async操作的延续\xd7\x93。

\n\n

所以:

\n\n
    \n
  1. 不,是一样的SyncrhonizationContext
  2. \n
  3. 不会,任务完成#11后,线路将在 UI 线程(未阻塞)上恢复,GetAsync从而完成GetPageStatus任务。然后线#4也会在 UI 线程上恢复。
  4. \n
\n\n

重要的是要理解SynchronizationContext在这种情况下,仅确保某些工作将由专用线程(串行)完成。只要线程可以自由地执行该工作单元,就永远不会发生死锁。

\n