跳過導航列

執行緒模型

您知道此網頁是由 Github Wiki 網頁自動產生 嗎?您可以自行透過 此處 來改善該網頁!

簡而言之,對於通道而言

  1. 無論其傳輸類型為何,其所有上游(即內向)事件都必須從執行該通道 I/O 的執行緒(即 I/O 執行緒)觸發。
  2. 所有下游(即外向)事件都可以從任何執行緒觸發,包含 I/O 執行緒與非 I/O 執行緒。然而,任何下游事件的副作用所觸發的上游事件都必須從 I/O 執行緒發射。(例如,如果 `Channel.close()` 觸發 `channelDisconnected`、`channelUnbound` 和 `channelClosed`,它們必須由 I/O 執行緒發射。

目前的問題 (UGLY - 會在上游處理常式中造成競爭狀態,BAD - 沒有造成競爭狀態,但違反預期的執行緒模型)

  • UGLY:下游事件的副作用所觸發的上游事件是由呼叫執行緒觸發的

  • UGLY:本機傳輸總是使用呼叫執行緒觸發事件。

  • 不佳:channelOpen 會觸發呼叫 ChannelFactory.newChannel() 的執行緒,這不是 I/O 執行緒。這有點不佳,但否則無法藉由此處關閉通道來限制並行活動通道。如果我們在 IO 執行緒中執行此項作業,效率就不會這麼高。

  • 不佳:用戶端通道由兩個 I/O 執行緒執行。一個執行連線嘗試,另一個執行實際 I/O。

動作項

  • 合併用戶端 Boss、伺服器端 Boss 和 NioWorker 到可以執行所有 I/O 作業的通用 I/O 執行緒中。這麼做會
    • 解決用戶端通道問題,因為嘗試建立連線的執行緒可以繼續執行讀取和寫入作業。
    • 解決 Netty 會建立與開啟伺服器埠數量一樣多執行緒的問題。
    • 我們可以更容易地共用 NioWorker 池,並可能在通道-工作執行緒對應中擁有更佳彈性。
    • 我們也需要查明是否可以建立抽象 I/O 執行緒類別,以便所有傳輸(socket、datagram、SCTP 等)都能延伸它。我們目前在 socket、datagram 和 SCTP 之間有太多重複內容。
  • 如果呼叫者執行緒不是 I/O 執行緒,則 Netty 會稍後在 I/O 執行緒中觸發上游事件。 همراه با اين تغيير,允許使用者稍後在 I/O 執行緒中觸發自己的上游事件,方法是將 `sendUpstreamLater()` 方法新增至 `ChannelPipeline` 和 `ChannelHandlerContext`。
    • 但是,我們無法僅在目前執行緒不是 I/O 執行緒時才使用 `sendUpstreamLater()`,因為 `OMATPE` 或 `MATPE` 會干擾它,所以我們必須讓使用者決定。(亦即呼叫 `sendUpstream()` 或 `sendUpstreamLater()`)
  • `ChannelFactory.newChannel()` 不得立即觸發事件。`newChannel()` 必須等到 I/O 執行緒通知通道已註冊至 I/O 執行緒,才會將新通道傳回給呼叫者。
  • 重新撰寫區域傳輸。

問題

  • 我們是否可以在 v3 中進行所有這些變更,並維持事物的向後相容性?在 v4 中完成這些作業豈不是比較容易?完全非同步使用者應用程式,於處理常程式中執行所有 I/O 並大量使用 `ChannelFuture` 不應受到目前有缺陷之執行緒模型的影響,這表示使用者可以設法解決此問題,因此最好移至 v4,而不是在兩個分支中進行相同的變更。

解答

  • 我認為如果將其「後援移植」至 v3 的工作量太大,我們應該直接繼續前進並對 v3「忽略」它。也許我們可以找出一些 v3 的「更簡單」解決方案,至少有助於我們擺脫 Channel.close() 競爭條件,因為這項競爭條件最有可能會影響我們的使用者。(normanmaurer)
最近於 2024 年 7 月 19 日檢索