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

元气小坏坏 提交于 2019-12-12 00:43:56

问题


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:


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


来源:https://stackoverflow.com/questions/31018115/control-not-yielding-after-task-result-in-a-non-async-block

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!