同步使用 nice .net 4.5 HttpClient 的最佳方式
best way to use the nice .net 4.5 HttpClient synchronously
我喜欢新的 System.Net.Http.HttpClient class。它有一个很好的简单 API,它不会抛出正常错误。但它只是异步的。
我需要运行的代码(深入服务器)
foo();
bar();
// compute stuff
var x = GetThingFromOtherServerViaHttp();
// compute more stuff
wiz(x);
classic 顺序同步代码。我看到了几个类似的 SO 问题,但实际上并没有说 'do this'。我看了
client.PostAsync.Wait()
全世界都在尖叫'dont do this'。怎么样:
client.PostAsync.Result()
这不就是变相的等待吗?
最后,我最终传递了一个处理结果的 lambda 回调,然后唤醒了显式等待 EventWaitHandle 的调用线程。很多管道。有没有更简单的东西,或者我应该回去使用旧的 http 客户端
编辑:进一步阅读后,我怀疑这段代码与 Wait 和 Result 有相同的问题,它只是一个更冗长的死锁
编辑:我最近让 MS PM 向我确认有一个授权 'any API that might take > X ms (I forgot X) must be async',许多 PM 将其解释为 'async only'(不清楚这是否是预期的)。因此文档数据库 api 只是异步的。
来自http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx:
return Task.Run(() => Client.PostAsync()).Result;
@Noseratio - of course I am concerned about deadlocks :-)
如果您在具有同步上下文的线程上,您只会担心死锁。
这通常是 UI 应用程序(客户端)的主线程,或者是处理 HTTP 请求(服务器端)的随机 ASP.NET 线程。无论哪种情况,您都不应该阻止它。
接受的答案可能有助于缓解僵局,但像这样阻止仍然会损害您的 UI 应用程序的最终用户体验(UI 将被冻结)或服务器端应用程序可扩展性(一个线程因阻塞而浪费,而它可能正在为另一个请求服务)。只是不要阻止并一直使用 async/await
。
您提到了 "deep inside a server" 但没有提供有关服务器端应用程序类型的详细信息。大多数现代服务器端框架都为 async/await
提供了良好的管道,因此采用它应该不是问题。
已更新 以解决评论:
I still dont like the fact that the same code written in different
places will deadlock. I would expect the wait call in a deadlock-prone
environment to throw
这不是 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)
。参考来源暗示:
https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpClient.cs
为什么要冒险?因为它应该比Task.Run(() => Client.PostAsync()).Result
.
轻一点
我不相信许多(任何?)其他库可以安全编码,并期待看到是否有人反对我的回答或更好但证明我错了。
我喜欢新的 System.Net.Http.HttpClient class。它有一个很好的简单 API,它不会抛出正常错误。但它只是异步的。
我需要运行的代码(深入服务器)
foo();
bar();
// compute stuff
var x = GetThingFromOtherServerViaHttp();
// compute more stuff
wiz(x);
classic 顺序同步代码。我看到了几个类似的 SO 问题,但实际上并没有说 'do this'。我看了
client.PostAsync.Wait()
全世界都在尖叫'dont do this'。怎么样:
client.PostAsync.Result()
这不就是变相的等待吗?
最后,我最终传递了一个处理结果的 lambda 回调,然后唤醒了显式等待 EventWaitHandle 的调用线程。很多管道。有没有更简单的东西,或者我应该回去使用旧的 http 客户端
编辑:进一步阅读后,我怀疑这段代码与 Wait 和 Result 有相同的问题,它只是一个更冗长的死锁
编辑:我最近让 MS PM 向我确认有一个授权 'any API that might take > X ms (I forgot X) must be async',许多 PM 将其解释为 'async only'(不清楚这是否是预期的)。因此文档数据库 api 只是异步的。
来自http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx:
return Task.Run(() => Client.PostAsync()).Result;
@Noseratio - of course I am concerned about deadlocks :-)
如果您在具有同步上下文的线程上,您只会担心死锁。
这通常是 UI 应用程序(客户端)的主线程,或者是处理 HTTP 请求(服务器端)的随机 ASP.NET 线程。无论哪种情况,您都不应该阻止它。
接受的答案可能有助于缓解僵局,但像这样阻止仍然会损害您的 UI 应用程序的最终用户体验(UI 将被冻结)或服务器端应用程序可扩展性(一个线程因阻塞而浪费,而它可能正在为另一个请求服务)。只是不要阻止并一直使用 async/await
。
您提到了 "deep inside a server" 但没有提供有关服务器端应用程序类型的详细信息。大多数现代服务器端框架都为 async/await
提供了良好的管道,因此采用它应该不是问题。
已更新 以解决评论:
I still dont like the fact that the same code written in different places will deadlock. I would expect the wait call in a deadlock-prone environment to throw
这不是 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)
。参考来源暗示:
https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpClient.cs
为什么要冒险?因为它应该比Task.Run(() => Client.PostAsync()).Result
.
我不相信许多(任何?)其他库可以安全编码,并期待看到是否有人反对我的回答或更好但证明我错了。