【问题标题】:HttpClient provide not truly async operations?HttpClient 提供的不是真正的异步操作?
【发布时间】:2016-10-10 21:38:43
【问题描述】:

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

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

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

但是,请避免库中的“虚假异步”。假异步是什么时候 一个组件有一个异步就绪的 API,但它只是由 将同步 API 包装在线程池线程中。那是 对 ASP.NET 上的可伸缩性会适得其反。一个突出的例子 假异步是 Newtonsoft JSON.NET,其他方面非常出色 图书馆。最好不要调用(假)异步版本 序列化 JSON;只需调用同步版本即可。一个 假异步的更棘手的例子是 BCL 文件流。当一个 文件流打开,必须显式打开异步 使用权;否则会使用假异步,同步阻塞 文件读取和写入的线程池线程。

他建议使用 HttpClient 但内部使用 Task.Factory.StartNew()

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

【问题讨论】:

    标签: c# asp.net multithreading asynchronous async-await


    【解决方案1】:

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

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

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

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

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

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

    附带说明一下,您发布的代码显示了一个dangerous use of StartNew,由于使用了TaskScheduler.Current,它实际上具有caused problems。 .NET Core 中的 has been fixed - 不确定修复何时会正确回滚到 .NET Framework。

    【讨论】:

    • 感谢您提供的信息,斯蒂芬。每次我认为我了解async/await属性时,你来了,我明白我什么都不知道。
    【解决方案2】:

    不,你的假设是错误的。

    1. StartNew isn't equal to the Run method.
    2. 此代码来自HttpClientHandler,而不是HttpClient,并且您没有检查此类中的this.startRequest 代码。您正在检查的代码是一个 prepare 方法,它在新线程池中启动一个任务,并在内部调用实际代码来启动一个 http 请求。
    3. HTTP-connection 不是在 .NET 抽象级别上创建的,我相信在 startRequest 中你会找到一些 P/Invoke 方法,它可以为:

      • DNS 查找
      • 套接字连接
      • 发送请求
      • 等待答复
    4. 如您所见,以上都是真正应该以异步方式调用的逻辑,因为它在.NET框架之外,并且某些操作可能非常耗时。这正是应该异步调用的逻辑,在等待它的过程中,.NET 线程正在ThreadPool 中释放以处理其他任务。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-11
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 2019-11-30
      • 1970-01-01
      相关资源
      最近更新 更多