2015-11-03 60 views
1

Stream.BeginRead()將回調函數作爲參數之一。該回調函數應該被異步調用,但.net通過直接調用BeginRead()中的回調函數來僞造。爲什麼會發生? Read()和BeginRead()之間似乎沒有區別。
請參考下面的堆棧視圖:爲什麼Stream.BeginRead()是同步的?

stack view

+0

假設有數據立即可用,爲什麼*不會*你想讓它同步回叫你? –

+0

fwiw,文檔(https://msdn.microsoft.com/en-us/library/system.io.stream.beginread(v=vs.110).aspx)在基礎'Stream.BeginRead ()'實現。 –

+2

IIRC默認流實現將所有異步調用傳遞到同步方法。這是由子類的實現者提供的異步方法實現。它們並不是默認的。您正在使用的Stream實現可能沒有APM方法的實現。基於任務的方法默認使用APM方法。 – spender

回答

1

由於the documentation for Stream表示:

的BeginRead的溪流上的默認實現調用Read方法同步,這意味着讀可能會阻止在一些溪流上。但是,如果實例已經異步打開,FileStream和NetworkStream等類的實例完全支持異步操作。因此,對BeginRead的調用不會阻塞這些流。 您可以覆蓋BeginRead(例如,通過使用異步委託)以提供異步行爲

換句話說,它是由每個Stream子類提供真正的異步行爲。

現在,你在堆棧跟蹤看到ConnectStream的情況下,這是另一個.NET類(內部,無證),它實際上提供異步執行的BeginRead()。這可以在the source code中看到。但是,異步操作通常還有另一個重要規則:異步操作the APM可能實際上完全同步完成。甚至有a property on IAsyncResult來表明這種情況。

事實上,事實證明許多異步API都是這種情況。例如,當使用await時,可能該方法將而不是返回到await表達式,而是將立即檢索完成結果並繼續在當前線程中執行。這種情況不僅發生在awaitable只是一個裝在異步包裝中的同步操作時,而且通常是一個異步操作實際上可以同步完成時。


我敢肯定,如果你要檢查你的回調IAsyncResult.CompletedSynchronously財產,你會發現它被設置爲true,因爲它應該在API同步完成異步操作是。該屬性主要存在於這種場景中,以防您自己的代碼需要區分異步完成的操作和同步完成的操作(通常,它不應該,但我們都知道代碼並非總是應該如此,甚至有時不能:))。

+0

以下部分根本不對:如果FileStream和NetworkStream等類的實例完全支持異步操作(如果實例已異步打開)。我知道這些文件是這麼說的,但事實並非如此。我想這只是衆多.net craps中的一個。 – moose

+0

@moose:請舉。因爲這兩個類都有很多使用異步操作的異步代碼示例。當然,FileStream需要使用FileOptions.Asynchronous。在那裏,如果你沒有正確初始化對象,你將不會得到你想要的行爲。但是'NetworkStream.BeginRead()'_always_直接到'Socket.BeginReceive()',它本身是絕對異步的。 –

+0

我不知道該說些什麼,但是我親眼看到了堆棧。它顯示的是同步的。根據文檔所述,我會說你可以使用BeginRead(),並且一些內部邏輯將決定它是異步還是同步。根本沒有用(對我來說)。 – moose