2009-07-10 58 views
1

我正在用C#編寫一個服務器,它創建一個(很長,甚至可能是無限)IEnumerable<Result>以響應客戶端請求,然後將這些結果傳回給客戶端。讓客戶端提取數據

我可以設置它,以便如果客戶端讀取速度很慢(或者一次完全可能幾秒鐘不讀),服務器將不需要等待緩衝區空間的線程停止清除這樣它可以拉動下一對Result,將它們序列化,並將它們填充到網絡中?

這是如何NetworkStream.BeginWrite的作品?關於何時調用回調方法,文檔不清楚(對我而言)。這是否基本上立即發生,只是在另一個線程,然後阻止EndWrite等待實際的寫作發生?當套接字API下溢中的某種較低級緩衝區發生時會發生嗎?數據實際寫入網絡時會發生嗎?它在被確認後會發生嗎?

我很困惑,所以有可能整個問題都是離題的。如果是這樣,你能轉過來指點我正確的方向來解決我所期望的是一個相當普遍的問題嗎?

回答

0

首先,您的主線程可以在其他工作完成時繼續執行的唯一方法是使用另一個線程。一個線程不能同時做兩件事。

但是,我認爲你想避免的是與Thread對象混淆,並且可以通過使用BeginWrite。根據你的問題

的文檔是不清楚(我) 什麼時候回調方法將 調用。

調用是在網絡驅動程序將數據讀入緩衝區後進行的。

是否發生根本立即 只是在另一個線程,然後在EndWrite 塊等待 實際寫入的情況發生?

不,直到它處於由網絡驅動程序處理的緩衝區中。

是否發生時,某種在套接字API 下溢 下級緩衝區?

如果通過下流你的意思它有空間,那麼是的。

當數據已被實際寫入網絡時,會發生這種情況嗎?

時是否已 承認這一點?

No.

編輯

個人而言,我會嘗試使用一個線程。 BeginWrite在幕後做了很多事情,你應該認識到......加上我很奇怪,我喜歡控制我的線程。

+0

這個問題中有一些信息不太準確。例如,正如我在我的文章中所解釋的那樣,只要數據到達發送緩衝區,回調並不總是被調用。這取決於實施,但即使在Windows上,也取決於IO完成端口是否可用。有時可能會立即調用它並阻止EndWrite。我還會補充說,爲每一次發送創建一個線程是不明智的。至少,使用線程池。但是,這只是讓事情變得複雜,而且最有可能的做法比BeginWrite的效率低。 – IRBMe 2009-07-12 09:08:28

2

我會更詳細地回答你問題的第三部分。

MSDN文檔指出:

當應用程序調用BeginWrite,該系統採用一個單獨的線程來執行指定的回調方法,並在EndWrite直到的NetworkStream塊發送請求的字節數或引發一個例外。

據我瞭解,在調用BeginSend後是否立即調用回調方法取決於底層實現和平臺。例如,如果IO完成端口在Windows上可用,則不會。線程池中的線程在調用之前將會阻塞。

事實上,NetworkStream的BeginWrite方法只是在我的.Net實現中調用底層套接字的BeginSend方法。 Mine在完成端口的情況下使用基礎WSASend Winsock函數。這使得它比僅僅爲每個發送/寫入操作創建自己的線程效率更高,即使您要使用線程池。

如果WSASend的結果是IOPending,Socket.BeginSend方法然後調用OverlappedAsyncResult.CheckAsyncCallOverlappedResult方法,該方法又調用本地RegisterWaitForSingleObject Win32函數。這將導致線程池中的一個線程阻塞,直到WSASend方法指示它已完成,然後調用回調方法。

由NetworkStream.EndSend調用的Socket.EndSend方法將等待發送操作完成。它必須這樣做的原因是因爲如果IO完成端口不可用,那麼將立即調用回調方法。

我必須再次強調這些細節是特定於我的.Net和我的平臺的實現,但這應該有希望給你一些見解。