C# “试图理解”;普通的;与ASP.NET和HttpClient()的异步死锁
在遇到“常见”异步死锁并从中获得进一步了解后,我尝试在ASP.NET中模拟这个问题,试图找出为什么我们以前从未遇到过这个问题。看起来不同的是,以前我们使用的是http客户机get ASYC方法,这并没有引起问题C# “试图理解”;普通的;与ASP.NET和HttpClient()的异步死锁,c#,asp.net,asynchronous,async-await,C#,Asp.net,Asynchronous,Async Await,在遇到“常见”异步死锁并从中获得进一步了解后,我尝试在ASP.NET中模拟这个问题,试图找出为什么我们以前从未遇到过这个问题。看起来不同的是,以前我们使用的是http客户机get ASYC方法,这并没有引起问题 public class DeadLockController : ApiController { /// <summary> /// Does not result in deadlock - but why?
public class DeadLockController : ApiController
{
/// <summary>
/// Does not result in deadlock - but why?
/// </summary>
[HttpGet]
public IHttpActionResult HttpDeadLock()
{
var client = new HttpClient();
return Ok( client.GetStringAsync( "https://www.google.com/" ).Result );
}
/// <summary>
/// Results in expected repeatable deadlock.
/// </summary>
[HttpGet]
public IHttpActionResult DeadLock()
{
var delayTask = DelayAsync().Result;
return Ok( delayTask );
}
/// <summary>
/// Does not result in deadlock.
/// </summary>
[HttpGet]
public async Task< IHttpActionResult > FixedDeadLock()
{
var delayTask = await DelayAsync();
return Ok( delayTask );
}
private async Task< int > DelayAsync()
{
await Task.Delay( 1000 );
return 0;
}
}
公共类死锁控制器:ApiController
{
///
///不会导致死锁-但为什么?
///
[HttpGet]
公共IHttpActionResult HttpDeadLock()
{
var client=新的HttpClient();
返回Ok(client.GetStringAsync(“https://www.google.com/(a)结果);
}
///
///导致预期的可重复死锁。
///
[HttpGet]
公共IHttpActionResult死锁()
{
var delayTask=DelayAsync().Result;
返回Ok(延迟任务);
}
///
///不会导致死锁。
///
[HttpGet]
公共异步任务FixedReadLock()
{
var delayTask=await DelayAsync();
返回Ok(延迟任务);
}
专用异步任务DelayAsync()
{
等待任务。延迟(1000);
返回0;
}
}
因此,如果要调用api/DeadLock/DeadLock
,就会遇到本文中描述的常见死锁。这是预期的/理解的api/DeadLock/FixedDeadLock
是解决这个问题的“正确”方法
然而,调用
api/DeadLock/HttpDeadLock
不会导致死锁,即使它们在概念上是相同的,我不知道为什么?为什么HttpClient没有遇到这个问题?理论上,Httpclient正在内部进行等待 api/DeadLock/HttpDeadLock不是死锁的原因是,在该代码中,您没有等待任何任务
而是通过调用task.Result同步等待任务来阻塞线程
在实现这种模式时,死锁通常会出现async await和Task.Wait/Task.Result组合。将DelayAsync更改为
await Task.Delay(1000)。ConfigureAwait(false)我打赌api/DeadLock/DeadLock
也不会再出现死锁。请阅读文章的“配置上下文”部分以获得一些解释。@ScottChamberlain谢谢-您也可以像我在FixedDeadLock()中所做的那样,使用wait来修复它函数也来源于那篇文章,因为上下文-问题是为什么HttpClient不会导致此问题?仅供参考-不是您问题的答案,但您应该阅读:出于好奇,您如何可靠地重现api/deadlock/deadlock
?i、 e.您是否有100个并发请求?内部HttpClient
一直都有.ConfigureAwait(false)
,以防止出现“不正确”的问题使用库如果每次点击api/deadlock/deadlock,它都会因为死锁而挂起。我想强调的一个关键点是,GetStringAsync
在内部不使用Wait
,生成任务的TaskCompletionSource
,然后只返回任务。@ScottChamberlain注释就是我想要的答案:)Thanks@ScottChamberlain我想说,真正的关键是它不会将其延续发布到当前的同步上下文中。(无需使用await
即可完成,或者即使使用await
也可以避免)