死锁使用异步和等待

use*_*955 4 .net c# http async-await

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

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

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

根据我的理解,我可以a)authorize()在调用异步方法时使用-keyword(这将挂起方法并在异步方法完成后继续),或者b)省略httpPost()-keyword而是调用异步方法的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);
}
Run Code Online (Sandbox Code Playgroud)

让我告诉你工作的例子:

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);
}
Run Code Online (Sandbox Code Playgroud)

我也试图让所有3种方法的非异步,并更换httpPost()为s awaitawaitS,但随后将在该行永远挂Task.Result

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

Ser*_*rvy 12

您有一个SynchronizationContext,并且当您await继续使用该上下文时,将捕获该上下文.

您正在启动异步任务,将调度安排在稍后的主环境中运行.

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

正如您在第一个示例中所做的那样,这就是"一直异步"的重要原因.

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