同步使用.net 4.5 HttpClient的最佳方式
本文关键字:HttpClient 最佳 方式 net 同步 | 更新日期: 2023-09-27 18:07:36
我喜欢新的System.Net.Http.HttpClient类。它有一个很简单的API,它不会抛出正常的错误。
我需要的代码(在服务器的深处)
foo();
bar();
// compute stuff
var x = GetThingFromOtherServerViaHttp();
// compute more stuff
wiz(x);
经典顺序同步代码。我看到了几个类似的SO问题,但实际上从来没有说过"做这个"。我看了
client.PostAsync.Wait()
全世界都在尖叫"不要这样做"。如何:
client.PostAsync.Result()
这不是伪装的等待吗?
最后,我最终传入了一个lambda回调,该回调处理了结果,然后唤醒了显式等待EventWaitHandle的调用线程。很多管道。有没有更简单的方法或者我应该回到使用旧的http客户端
编辑:在进一步阅读后,我怀疑这段代码有相同的问题,等待和结果,它只是一个更冗长的死锁编辑:我最近有MS PM向我确认,有一个命令"任何可能需要> X MS(我忘了X)的API必须是异步的",许多PM将其解释为"仅异步"(不清楚这是否是什么意思)。因此Document DB api只能async。
From http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx:
return Task.Run(() => Client.PostAsync()).Result;
@Noseratio -当然我关心死锁:-)
只有当你在一个具有同步上下文的线程上时,你才会关心死锁。
通常是UI应用程序(客户端)的主线程,或者随机的ASP。. NET线程处理HTTP请求(服务器端)。无论哪种情况,你都不应该阻塞它。
被接受的答案可能有助于缓解死锁,但是像这样的阻塞仍然会损害UI应用程序的最终用户体验(UI将被冻结),或者服务器端应用程序的可伸缩性(阻塞浪费了一个线程,而它可能正在服务另一个请求)。只是不要阻塞,一直使用async/await
。
你提到"服务器内部深处",但没有详细说明这是哪种服务器端应用程序。大多数现代服务器端框架都有很好的async/await
管道,所以接受它应该不是问题。
更新以解决注释:
我仍然不喜欢用不同的语言写相同的代码地方将陷入僵局。我认为在容易死锁的情况下应该使用wait调用抛出
的环境
这不是async/await
的问题,而是同步上下文概念的问题,当它与阻塞代码一起使用时。下面是一个简单的死锁:
private void Form1_Load(object sender, EventArgs e)
{
var mre = new System.Threading.ManualResetEvent(initialState: false);
System.Threading.SynchronizationContext.Current.Post(_ =>
mre.Set(), null);
mre.WaitOne();
MessageBox.Show("We never get here");
}
理论上,可以尝试减轻SynchronizationContext.Post
内部潜在的死锁,例如通过检查Thread.ThreadState == System.Threading.ThreadState.WaitSleepJoin
。然而,这并不是一个100%可靠的解决方案。
有争议的是,对于System.Net.Http.HttpClient
,您可能可以直接使用.Result
Microsoft 应该遵循他们自己的建议,在该库中一直使用.ConfigureAwait(false)
。参考来源暗示:
为什么要冒这个险?因为它应该比Task.Run(() => Client.PostAsync()).Result
稍微轻一些。
我不相信许多(任何?)其他库是安全编码的,并期待看到是否有人反对我的答案或更好地证明我错了。