2017-07-16 87 views
2

我有一個使用SocketAsyncEventArgs異步接收UDP數據包的標準實現。我不明白從文檔和一些谷歌搜索是,如果我應該在回調本身內處理消息的真實工作,如我指的完整實現中的this comment indicates,或者我應該將處理卸載到其他線程,例如通過ConcurrentQueue或BlockingCollection。在哪些線程上調用SocketAsyncEventArgs完成並處理消息

我關注的是以下幾點:

  • 如果直接在回調處理,可以把它降低接收性能或引入由於臨時線程池飢餓或其他一些實現細節隨機延遲?
  • 由於處理過程中的輕微延遲(而不是僅僅卸載到一個集合)可能會由於緩衝區而丟棄更多的包?
  • 是否可以按照與包實際上從網絡到達不同的順序調用回調的意義來重新排序更多包。

那麼,什麼是最好的做法或加工使用的SocketAsyncEventArgs保證最低錯過的數據報,回調調用沒有額外的重新排序,沒有額外的延遲消息的預期呢?

和一個相關的問題 - 是否ReceiveAsync保證任何命令或至少嘗試調用回調以相同的順序,從網絡接收包,或者我應該使用阻止接收的呢?目標用例是訂閱6-8個UDP通道,其中每個通道的順序非常重要。運行一些阻塞線程看起來比處理回調要複雜得多,但如果只有這樣的解決方案可以保證消息順序,那就不那麼難。

回答

3

什麼是最好的做法,或使用的SocketAsyncEventArgs保證最低錯過的數據報

坦白處理消息的預期的方式,這是真正的意見在一定程度上的問題,以及非常依賴於你的確切場景。作爲一般規則,你的I/O完成例程應該很快。如果你的處理速度很快,那麼在例程中就可以這麼做了。如果沒有,你應該儘可能少地做些工作,即把數據移動到一個隊列中,然後在其他地方處理,然後從完成例程返回。

請記住,這裏的「快速」是相對的。你只需要比網絡更快,儘管網絡速度不斷提高,但在現代CPU上卻不是很難做到。網絡層將代表您進行緩衝,因此假設您的工作負載吞吐量大於網絡上的吞吐量,那麼在完成例程中完成這項工作可能很不錯。

但真的,它只是取決於。通常沒有辦法說哪個更好。每種特定情況都不相同。

ReceiveAsync是否保證任何訂單或至少嘗試以與從網絡接收包相同的順序調用回調,或者我應該使用阻止接收的呢?

阻擋接收將無濟於事。

異步方法都具有相同的特徵:您可以一次發佈多個異步方法,並且它們將按照它們的發佈順序完成。但是您仍然需要跟蹤您發佈讀取操作的順序。緩衝區將按照您給予網絡層的順序填充,但完成例程可能不按順序執行,因爲它們在線程上執行,並且線程調度程序不保證線程執行的順序。只是因爲一個線程在另一個線程之前可以運行,這並不意味着它會在另一個線程之前實際得到它的下一個時間片。

但它實際上更糟糕:

目標的使用情況是訂閱6-8 UDP通道,在每個人的順序是非常重要的。

如果訂單在您的業務情景中很重要,那麼您需要在數據報中包含序列號,並確保在收到這些數據報時使用這些序列號以正確的順序排列數據。

UDP不保證排序。數據報可以以任何順序接收,與發送順序無關。 UDP也不保證傳送。數據報可能隨時丟失。 UDP也不保證唯一性。給定的數據報可以被多次傳送。

如果可靠性和排序在您的方案中很重要,那麼您可能應該使用TCP,而不是UDP。

如果你唯一關心的是訂購,那麼UDP可能仍然適用於你。在這種情況下,由於無論如何您都需要在數據報中使用序列號,所以它確實使「多個併發讀取操作」場景更簡單,因爲數據本身帶有序列號,因此您無需分別跟蹤(例如在與每個讀取操作相關聯的狀態對象中)。

+0

謝謝!序列號已由外部數據源(交換)提供,並且無論如何將存在恢復順序的邏輯,並且TCP不是一個選項。所以你說在任何意義上,循環中的阻塞讀取都不比ReceiveAsync更可靠? –

+0

_「在任何意義上來說,循環中的阻塞讀取都不如ReceiveAsync可靠嗎?」 - 「在任何意義上」都非常廣泛。循環中的阻塞讀取肯定可以更容易地進行正確編碼,所以至少肯定它在這個「意義上」是「更可靠的」。此外,即使使用異步讀取,您也可以選擇一次只有一個未完成的讀取操作,這在語義上與具有阻止讀取的循環相同; ... –

+0

...唯一的區別是更好的可伸縮性和缺乏線程阻塞,並且實現在某種意義上是簡單的(和TCP相比,多個併發讀取操作在實踐中更簡單)。但是,是的......從某種意義上說,對於使用UDP的情況,您必須處理亂序數據,從而引入讀取完成例程相對於讀取操作本身實際完成的順序執行的可能性,比一般用_any_其他讀取實現來處理UDP。 –

相關問題