死锁使用async&等待

时间:2013-09-05 15:01:43

标签: c# .net http async-await

我想在程序中实现的是以下callstack / workflow:

  1. 调度()
  2. 授权()
  3. httpPost()
  4. 我的想法是,httpPost()将是异步的,而其他2种方法仍然是非同步的。但是,出于某种原因,除非我做了2 + 3,否则它对我不起作用。异步。也许我还有一些误解。

    根据我的理解,我可以a)在调用异步方法时使用await - 关键字(这将挂起方法并在异步方法完成后继续),或b)省略await -keyword,而是调用async方法的Task.Result返回值,该值将一直阻塞,直到结果可用。


    让我告诉你工作的例子:

        private int dispatch(string options)
        {
           int res = authorize(options).Result;
           return res;
        }
    
        static async private Task<int> authorize(string options)
        {
            string values= getValuesFromOptions(options);
    
            KeyValuePair<int, string> response = await httpPost(url, values);
    
            return 0;
        }
    
      public static async Task<KeyValuePair<int, string>> httpPost(string url, List<KeyValuePair<string, string>> parameters)
      {
         var httpClient = new HttpClient(new HttpClientHandler());
    
         HttpResponseMessage response = await httpClient.PostAsync(url, new FormUrlEncodedContent(parameters));
    
         int code = (int)response.StatusCode;
    
         response.EnsureSuccessStatusCode();
    
         string responseString = await response.Content.ReadAsStringAsync();
    
         return new KeyValuePair<int, string>(code, responseString);
      }
    

    让我向您展示 - 工作示例:

        private int dispatch(string options)
        {
           int res = authorize(options).Result;
           return res;
        }
    
        static private int authorize(string options)
        {
            string values= getValuesFromOptions(options);
    
            Task<KeyValuePair<int, string>> response = httpPost(url, values);
    
            doSomethingWith(response.Result);    // execution will hang here forever
    
            return 0;
        }
    
      public static async Task<KeyValuePair<int, string>> httpPost(string url, List<KeyValuePair<string, string>> parameters)
      {
         var httpClient = new HttpClient(new HttpClientHandler());
    
         HttpResponseMessage response = await httpClient.PostAsync(url, new FormUrlEncodedContent(parameters));
    
         int code = (int)response.StatusCode;
    
         response.EnsureSuccessStatusCode();
    
         string responseString = await response.Content.ReadAsStringAsync();
    
         return new KeyValuePair<int, string>(code, responseString);
      }
    

    我还试图让所有3种方法都是非同步的,并用await替换httpPost中的.Result,但它会永久地挂在行{{1 }}

    有人可以启发我并解释我的错误是什么吗?

1 个答案:

答案 0 :(得分:11)

您有一个SynchronizationContext,并且在await时正在捕获该上下文,以便继续在该上下文中运行。

您正在启动异步任务,计划在以后的某个时间点在主要上下文中运行。

然后,在异步操作完成之前,您的主上下文中的代码会对异步操作执行阻塞等待。无法安排继续运行,因为上下文正忙于等待继续。经典僵局。

这就是为什么“像你在第一个例子中所做的那样”一直“异步”的原因。

在第二个例子中,有一些黑客可以解决僵局,但它仍然不是你应该做的事情。异步的整个过程就是避免阻塞你的线程。如果你只是对任务进行阻塞等待,那么你就是在打败异步的目的。除非你没有选择,否则要么一切都是异步的,要么都不是异步的。