死锁使用异步和放大器;等待 [英] Deadlock using async & await

查看:119
本文介绍了死锁使用异步和放大器;等待的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想实现我的计划是以下调用堆栈/工作流程:

What I want to realize in my program is the following callstack/workflow:

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

我的想法是,该 httpPost()将是异步,而其他两种方法仍非异步。然而,出于某种原因,它不会为我工作,除非我做了2 + 3。异步。也许我还是有一些误解。

My idea was, that httpPost() will be async, while the other 2 methods remain non-async. However, for some reason, it would not work for me unless I made 2.+3. async. Maybe I still have some misunderstandings.

据我了解我可以a)使用等待 -keyword调用异步方法(这将暂停方法,并继续异步方法完成后)时,或B)ommit的等待 -keyword,而是调用的异步方法Task.Result返回值,这将阻塞,直到结果可用。

To my understanding I can either a) use the await-keyword when calling the async method (this will suspend the method and continue after the async method completes), or b) ommit the await-keyword and instead call Task.Result of the async methods return value, which will block until the result is available.

让我告诉你的工作例如:

Let me show you the working example:

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


让我告诉你在木材加工例如:


Let me show you the non-working example:

    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种方法的非异步,并与<替换等待 S在 httpPost code>。结果 S,但它会永远挂在该行的Htt presponseMessage响应= httpClient.PostAsync(URL,新FormUrlEn codedContent (参数))结果。

I also tried to have all 3 methods non-async, and replacing the awaits in httpPost with .Results, but then it will hang forever in the line HttpResponseMessage response = httpClient.PostAsync(url, new FormUrlEncodedContent(parameters)).Result;

可能有人开导我,并解释我的错误是?

Could someone enlighten me and explain what my mistake is?

推荐答案

您有一个的SynchronizationContext ,并且这种情况下被抓获时,等待,这样的延续(S)可以在上下文中运行。

You have a SynchronizationContext, and that context is being captured when you await so that the continuation(s) can run in that context.

您已经开始一个异步任务,调度continutation在你的主要方面在以后的某个点运行。

You're starting an async task, scheduling a continutation to run in your main context at some later point.

然后,异步操作完成之前,你有code在主背景下做的异步操作的阻塞等待。延续无法安排运行,因为上下文是忙等待的延续。经典的僵局。

Then, before the async operation is done, you have code in your main context doing a blocking wait on the async operation. The continuation cannot be scheduled to run because the context is busy waiting on the continuation. Classic deadlock.

这就是为什么它是重要的异步一路上涨,你在你的第一个例子。

This is why it's important to "async all the way up", as you did in your first example.

有一些黑客,可以解决在第二个例子中的僵局,但它仍然不是你应该做的事情。要去异步整点是为了避免堵塞你的线程(S)。如果你只是去上做反正你击败的去异步的目的,任务阻塞等待。要么让一切异步的,或没有异步的,除非你没有选择。

There are a few hacks that can work around the deadlock in the second example, but it's still not something you should be doing. The entire point of going asynchronous is to avoid blocking your thread(s). If you just go doing a blocking wait on the task anyway you're defeating the purpose of going asynchronous. Either make everything asynchronous, or nothing asynchronous, unless you don't have a choice.

这篇关于死锁使用异步和放大器;等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆