在非异步块中 Task.Result 后控制不屈服

Control Not yielding after Task.Result in a non Async Block

我正在试验 MSDN 样本。我遇到了以下问题。当 运行 来自按钮单击事件处理程序的 async 代码块时,使用 async 模式,它工作正常 (button1_Click)。但是对于 button2_Click,控制不会超出 TaskObj.Result。可能是什么原因?

  private async void button1_Click(object sender, EventArgs e)//this works fine
    {
        Task<int> TaskObj = AccessTheWebAsync();
        string a ="I came here..";

        int y = await TaskObj;

        string a1 = "I came here also..";
    }

    private  void button2_Click(object sender, EventArgs e)//this is not working
    {
        Task<int> TaskObj = AccessTheWebAsync();
        string a = "I came here..";//control yielded here
        int y = TaskObj.Result;//something happened here
        string a1 = "Why I couldn't come here?";//why control is not reaching here?
    }


    async Task<int> AccessTheWebAsync()
    { 
        HttpClient client = new HttpClient();
        Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com");        
        DoIndependentWork();
        string urlContents = await getStringTask;
        return urlContents.Length;
    }

    private void DoIndependentWork()
    {
      IList<Int32>intK = Enumerable.Range(1, 100000000).ToList();
      foreach (int x in intK)
      {
          int y = x * 2;
      }
    }

What might be the reason for the same?

区别在于一个死锁,而另一个则没有。当您 await 时,您 异步等待 通过将控制权交还给调用方法。当您使用 Task.Result 时,您会同步阻塞调用。这会导致僵局。

为什么?因为这里涉及到一个叫做 "Synchronization Context" 的东西,它负责在它之前使用的相同上下文中执行你的延续(第一个 await 之后的所有代码)的一些魔法,这在你的案例是 UI 线程 。因为您与 Task.Result 同步阻塞,continuation 无法将自己编组回 UI 线程,因为它在 .Result.

等待自己

相反,使用 await 与您之前点击的按钮一样:

private async void button2_Click(object sender, EventArgs e)//this is not working
{
    Task<int> TaskObj = AccessTheWebAsync();
    string a = "I came here..";//control yielded here
    int y = await TaskObj;
}