Stream.BeginRead()将回调函数作为参数之一。该回调函数应该异步调用,但.net通过直接从BeginRead()调用回调函数来伪造它。为什么会这样?看起来Read()和BeginRead()之间没有区别 请参阅下面的堆栈视图:
答案 0 :(得分:1)
由于the documentation for Stream
表示:
流上的BeginRead的默认实现同步调用Read方法,这意味着Read可能会阻塞某些流。但是,如果实例已异步打开,则FileStream和NetworkStream等类的实例完全支持异步操作。因此,对BeginRead的调用不会阻止这些流。 您可以覆盖BeginRead(例如,通过使用异步委托)来提供异步行为。
换句话说,每个Stream
子类都可以提供真正的异步行为。
现在,对于您在堆栈跟踪中看到的ConnectStream
,这是另一个.NET类(内部的,未记录的),实际上 提供了{{的异步实现1}}。这可以在the source code中看到。但是,通常还有另一个重要的异步操作规则:{strong> the APM之后的异步操作实际上可能同步完成。甚至a property on IAsyncResult表示发生这种情况。
事实证明,许多异步API都是这种情况。例如,当使用BeginRead()
时,该方法可能不返回await
表达式,而是立即检索完成结果并继续执行当前的线程。这种情况不仅发生在awaitable只是一个异步包装器中的同步操作时,而且当通常异步操作通常可以同步完成时。
我敢肯定,如果你要检查回调中的await
属性,你会发现它被设置为IAsyncResult.CompletedSynchronously
,因为它应该是API同步完成异步操作的时候。该属性主要存在于这种情况下,以防您自己的代码需要区分异步完成的操作和同步完成的操作(通常,它不应该,但我们都知道代码并不总是应该如此,甚至有时候不能:))。