Ale*_*x K 3 c# deadlock task async-await dotnet-httpclient
我试图绕过同步调用异步函数和死锁.
在下面的例子中,我阻止了一个内部使用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);
}
}
Run Code Online (Sandbox Code Playgroud)
你能解释一下这两个电话有什么区别吗?
你在UI线程中.从该线程中调用Task.FromResult并创建任务.然后,您可以向需要在UI线程中运行的任务添加延续.该延续被添加到队列中以供消息泵处理.
然后等待该延续在UI线程中完成.该延续正在等待UI可用,以便甚至启动延续的主体,这将最终调用GetAsync.这是一个僵局.
连续的身体是什么并不重要; 以下代码死锁的原因相同:
private void GetBlocking_Click(object sender, RoutedEventArgs e)
{
Task.FromResult(true)
.ContinueWith(t =>{ },
TaskScheduler.FromCurrentSynchronizationContext())
.Wait();
}
Run Code Online (Sandbox Code Playgroud)
至于修复,你不应该首先同步等待异步操作.要么使整个事物异步,要么使它全部同步.