Control Not yielding after Task.Result in a non As

2019-08-24 13:16发布

This question already has an answer here:

I was experimenting with an MSDN sample. I came across the following issue. When running an async block of code from a button click event handler, with async pattern, it works fine (button1_Click). But for button2_Click, the control is not going beyond TaskObj.Result. What might be the reason for the same?

  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;
      }
    }

1条回答
甜甜的少女心
2楼-- · 2019-08-24 14:11

What might be the reason for the same?

The difference is one deadlocks, while the other doesn't. When you await, you asynchronously wait by yielding control back to the calling method. When you use Task.Result, you synchronously block on the call. This leads to a deadlock.

Why? because there is something called a "Synchronization Context" involved here, which is responsible for some of the magic of executing your continuation (all the code after the first await) inside the same context it previously used, which in your case is the UI thread. Because you block synchronously with Task.Result, the continuation is unable to marshal itself back onto the UI thread, since it is waiting on itself at the .Result.

Instead, use await as with your previous button click:

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;
}
查看更多
登录 后发表回答