死锁使用异步和等待

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

  1. 调度()
  2. 授权()
  3. httpPost()

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

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


让我告诉你工作的例子:

  private int dispatch(string options) { int res = authorize(options).Result; return res; } static async private Task authorize(string options) { string values= getValuesFromOptions(options); KeyValuePair response = await httpPost(url, values); return 0; } public static async Task<KeyValuePair> httpPost(string url, List<KeyValuePair> 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(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> response = httpPost(url, values); doSomethingWith(response.Result); // execution will hang here forever return 0; } public static async Task<KeyValuePair> httpPost(string url, List<KeyValuePair> 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(code, responseString); } 

我还试图让所有3个方法都是非异步的,并用httpPost s替换httpPostawait s,但是它会永久挂起HttpResponseMessage response = httpClient.PostAsync(url, new FormUrlEncodedContent(parameters)).Result;

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

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

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

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

这就是为什么像你在第一个例子中那样“一直异步”的重要性。

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