在任务延续中阻止异步 HttpClient 调用时出现死锁

本文关键字:调用 死锁 HttpClient 异步 延续 任务 | 更新日期: 2023-09-27 18:36:33

我正在尝试同步调用异步函数和死锁。

在下面的示例中,我阻止了一个内部使用 ConfigureAwait(false) 的异步调用,据我所知,它应该可以防止死锁。对 Web 服务的第一次调用不会死锁。但是,在同步回 UI 线程死锁的延续中发生的第二个事件。

GetBlocking_Click是 WPF 应用中的单击事件,因此第一个和第二个请求都发生在 UI 线程上。

      private void GetBlocking_Click(object sender, RoutedEventArgs e)
    {
        const string uri = "http://www.mywebservice.com";
        var example1 = GetAsync(uri).Result;
        Task.FromResult(true)
            .ContinueWith(t =>
            {
                var example2 = GetAsync(uri).Result;
            }, 
            TaskScheduler.FromCurrentSynchronizationContext()).Wait();
    }
    private async Task<string> GetAsync(string url)
    {
        using (var client = new HttpClient())
        {
            var responseMessage = await client.GetAsync(url).ConfigureAwait(false);
            return await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
        }
    }

你能解释一下这两个电话有什么区别吗?

在任务延续中阻止异步 HttpClient 调用时出现死锁

你在 UI 线程中。 从该线程调用Task.FromResult并创建任务。 然后,向需要在 UI 线程中运行的任务添加延续。 该延续将添加到队列中,供消息泵处理。

然后等待该延续在 UI 线程中完成。 该延续正在等待 UI 可用,以便甚至启动延续的正文,最终将调用 GetAsync . 这是一个僵局。

延续的主体是什么甚至无关紧要;出于同样的原因,以下代码死锁:

private void GetBlocking_Click(object sender, RoutedEventArgs e)
{
    Task.FromResult(true)
        .ContinueWith(t =>{ }, 
            TaskScheduler.FromCurrentSynchronizationContext())
        .Wait();
}

至于修复,您首先不应该同步等待异步操作。 要么使整个事情异步,要么使所有事情同步。