我对异步IO操作感到困惑。在this article Stephen Cleary解释说我们不应该使用Task.Run(() => SomeIoMethod())
因为真正的异步操作应该使用
.NET中的标准P / Invoke异步I / O系统
http://blog.stephencleary.com/2013/11/there-is-no-thread.html
但是,避免库中的“假异步”。假异步就是什么时候 一个组件有一个async-ready API,但它只是通过实现 将同步API包装在线程池线程中。那是 对ASP.NET的可伸缩性起反作用。一个突出的例子 假异步是Newtonsoft JSON.NET,非常出色 图书馆。最好不要调用(假的)异步版本 序列化JSON;只需调用同步版本。一个 伪异步的一个棘手的例子是BCL文件流。当一个 文件流打开后,必须显式打开异步 访问;否则,它将使用伪异步,同步阻塞 文件上的线程池线程读写。
他建议使用HttpClient但内部使用Task.Factory.StartNew()
这是否意味着HttpClient
未提供真正的异步操作?
答案 0 :(得分:4)
这是否意味着HttpClient不提供真正的异步操作?
排序。 HttpClient
处于不寻常的位置,因为它的主要实现使用HttpWebRequest
,它只是部分异步。
特别是,DNS查找是同步的,我想也许是代理解析。在那之后,它都是异步的。因此,对于大多数方案,DNS速度很快(通常是缓存的),并且没有代理,因此它以异步方式运行。不幸的是,有足够的场景(特别是来自公司网络内部),同步操作可能导致显着的延迟。
因此,当团队撰写HttpClient
时,他们有三个选择:
HttpWebRequest
(和朋友)允许完全异步操作。不幸的是,这会破坏相当数量的代码。由于继承在这些对象中用作扩展点的方式,添加异步方法将是向后兼容的。HttpWebRequest
等价物。不幸的是,这需要很多的工作,并且它们会失去与现有WebRequest
相关代码的所有互操作性。在理想世界中(即,当我们有无限的开发人员和测试人员时间时),我更愿意(2),但我理解为什么他们选择(3)。
在旁注中,您发布的代码显示dangerous use of StartNew
,由于使用TaskScheduler.Current
, 实际上caused problems。 .NET Core中的这个has been fixed - 不确定该修补程序何时会回滚到.NET Framework中。
答案 1 :(得分:0)
不,你的假设是错误的。
StartNew
isn't equal to the Run
method. HttpClientHandler
,而不是HttpClient
,您没有检查此类中的this.startRequest
代码。您正在检查的代码是一个prepare方法,它在新线程池中启动一个任务,在内部调用实际代码以启动一个http请求。 HTTP连接不是在.NET抽象级别上创建的,我确信在startRequest
内你找到一些P/Invoke
方法,它将为:
ThreadPool
中发布以处理其他任务。