HttpClient 不提供真正的异步操作吗?

kri*_*per 5 c# asp.net multithreading asynchronous async-await

我对异步 IO 操作感到困惑。在本文中中,Stephen Cleary 解释说我们不应该使用,Task.Run(() => SomeIoMethod())因为真正的异步操作应该使用

\n\n
\n

.NET 中的标准 P/Invoke 异步 I/O 系统

\n
\n\n

http://blog.stephencleary.com/2013/11/there-is-no-thread.html

\n\n
\n

但是,请避免在库中使用 \xe2\x80\x9c 伪造异步\xe2\x80\x9d。假异步是指组件具有异步就绪 API,但它只是通过将同步 API 包装在线程池线程中来实现。这对于 ASP.NET 的可扩展性来说会适得其反。假异步的一个突出例子是 Newtonsoft JSON.NET,这是一个优秀的库。最好不要调用(假)异步版本来序列化 JSON;只需调用同步版本即可。假异步的一个更棘手的例子是 BCL 文件流。当打开文件流时,必须显式打开它以进行异步访问;否则,它将使用假异步,同步阻塞\n线程池线程对文件的读写。

\n
\n\n

他建议使用 HttpClient 但内部使用Task.Factory.StartNew()\n在此输入图像描述

\n\n

这是否意味着它HttpClient不提供真正的异步操作?

\n

Ste*_*ary 4

这是否意味着 HttpClient 不提供真正的异步操作?

有点。HttpClient处于一个不寻常的位置,因为它的主要实现使用HttpWebRequest,它只是部分异步的。

特别是,DNS 查找是同步的,我想也许代理解析也是同步的。之后,一切都是异步的。因此,对于大多数情况,DNS 速度很快(通常会缓存)并且没有代理,因此它是异步运行的。不幸的是,在很多情况下(特别是在企业网络内),同步操作可能会导致严重的延迟。

所以,当团队写作时HttpClient,他们有三个选择:

  1. 修复HttpWebRequest(和朋友)允许完全异步操作。不幸的是,这会破坏相当多的代码。由于继承在这些对象中用作扩展点的方式,添加异步方法将是向后不兼容的。
  2. 写出他们自己的HttpWebRequest等价物。不幸的是,这需要大量工作,并且它们会失去与现有相关代码的所有互操作性WebRequest
  3. 将请求排队到线程池以避免最坏的情况(阻塞 UI 线程上的同步代码)。不幸的是,这会产生副作用,即降低 ASP.NET 的可伸缩性、依赖于空闲线程池线程,并且即使在最佳情况下也会产生最坏情况下的成本。

在理想的世界中(即,当我们有无限的开发人员和测试人员时间时),我更喜欢(2),但我理解他们为什么选择(3)。

顺便说一句,您发布的代码显示了 的危险使用StartNew,这实际上由于使用TaskScheduler.Current. 此问题已在 .NET Core 中修复 - 不确定修复何时会回滚到 .NET Framework 中。