死锁而阻断异步HttpClient的任务延续中调用 [英] Deadlock while blocking async HttpClient call within a task continuation

查看:710
本文介绍了死锁而阻断异步HttpClient的任务延续中调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想换我的头周围同步异步调用函数和僵局。

I am trying to wrap my head around synchronously calling async functions and deadlock.

在下面的例子中,我阻止一个异步调用内部使用ConfigureAwait(假)的,据我可以告诉应prevent僵局。以Web服务的第一次调用不会死锁。然而,第二个是一个同步回UI线程死锁延续内发生的。

In the below example I am blocking an async call which internally uses ConfigureAwait(false) which as far as I can tell should prevent deadlock. The first call to the web service does not deadlock. However, the second one that happens within a continuation that syncs back to the UI thread deadlocks.

GetBlocking_Click是一个WPF应用程序点击事件,使第一和第二个请求发生在UI线程上。

GetBlocking_Click is a click event in a WPF app so both the first and the second request happen on the UI thread.

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

能否请您解释一下什么是这2个呼叫之间的区别?

Can you please explain what is the difference between these 2 calls?

推荐答案

您是在UI线程。从该线程调用 Task.FromResult 和创建任务。然后,继续添加需要在UI线程中运行任务。该延续被添加到队列的消息泵来处理。

You're in the UI thread. From that thread you call Task.FromResult and create a task. You then add a continuation to that task that needs to run in the UI thread. That continuation is added to the queue for the message pump to handle.

您再等待延续在UI线程中完成。这延续正在等待UI,以便甚至开始延续的身体,这最终会调用 GetAsync 可供。这是一个僵局。

You then wait for that continuation to finish in the UI thread. That continuation is waiting for the UI to be available in order to even start the body of the continuation, which will end up calling GetAsync. This is a deadlock.

它甚至没有关系的延续身体是什么;以下code死锁出于同样的原因:

It doesn't even matter what the body of the continuation is; the following code deadlocks for the same reason:

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

至于修复,你刚才不应该摆在首位的异步操作同步等待。要么使整个事情异步,或使其所有同步。

As for the fix, you just shouldn't be synchronously waiting on asynchronous operations in the first place. Either make the whole thing asynchronous, or make it all synchronous.

这篇关于死锁而阻断异步HttpClient的任务延续中调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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