4

我希望我的程序遵循这个调用堆栈/工作流程:

  1. dispatch()
  2. authorize()
  3. httpPost()

我的想法是这httpPost()将是异步的,而其他 2 种方法仍然是非异步的。但是,由于某种原因,除非我使 2 和 3 异步,否则它将无法工作。也许我还有一些误解。

据我了解,我可以:

  1. 在调用异步方法时使用await关键字(这将暂停该方法并在异步方法完成后继续),或者
  2. 省略await关键字,而是调用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 种方法都非异步,将awaitshttpPost替换为.Results,但随后它永远挂在了线上HttpResponseMessage response = httpClient.PostAsync(url, new FormUrlEncodedContent(parameters)).Result;

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

4

1 回答 1

12

您有一个, 并且当您可以在该上下文中运行SynchronizationContext时,该上下文将被捕获。await

你正在启动一个异步任务,安排一个后续在你的主上下文中运行。

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

这就是为什么“一直异步”很重要的原因,就像您在第一个示例中所做的那样。

在第二个示例中,有一些技巧可以解决死锁,但这仍然不是您应该做的事情。异步的全部意义在于避免阻塞你的线程。如果你只是对任务进行阻塞等待,那么你就违背了异步的目的。要么让一切异步,要么不异步,除非你别无选择。

于 2013-09-05T15:05:35.503 回答