1. 程式人生 > >《Netty官方文件》5.0中的變化和注意點

《Netty官方文件》5.0中的變化和注意點

原文地址  譯者:葉揚V

這篇文件將引領你瞭解netty4.1 release版本之後所做的一系列顯著升級和新特性,以便讓你能把應用升級到新版本。

不像netty3.X4.0之間的升級變化,5.0版本雖然在設計上做出了重大突破和簡化,但(在呼叫層面)並沒有改變很多。我們儘可能讓4.X版本可以平滑地升級到5.0版本,但是如果你在升級過程中遇到任何問題,請告知我們。

變化要點

精簡handler型別繼承關係

ChannelInboundHandler和ChannelOutboundHandler被合併成ChannelHandler。現在ChannelHandler中既有inbound handler函式也有outbound handler函式。

ChannelInboundHandlerAdapterChannelOutboundHandlerAdapterChannelDuplexHandlerAdapter被棄用然後替換為

因為現在已經無法區分一個handlerinbound handler還是outbound handler,所以CombinedChannelDuplexHandler已經被替換為

channelRead0() → messageReceived()

我知道,這(譯者注:netty4中的channelRead0())是一個愚蠢的錯誤。如果你已經使用了,你就必須將channelRead0()函式重新命名為messageReceived()

更靈活的執行緒模型

Netty 4.X中,每個都與一個固定的執行緒緊密耦合,這個執行緒會執行它註冊的的所有I/O事件,也會執行所有提交給它的任務。

5.0版本開始,一個EventLoop(的構造)不再直接使用執行緒,取而代之的是使用。也就是說,它使用Executor物件作為建構函式的入參。而且,以前的方式是在迴圈中拉取I/O事件,現在的方式是每次迭代得到一個task,再將task提交給Executor執行。

如果沒有特別指定的話,Executor預設是一個ForkJoinPool的特點是使用thread-local佇列。也就是說,一個從執行緒A提交到ForkJoinPool的任務非常可能再次被執行緒A

執行。這極大的提高了EventLoops的執行緒關聯性。

而且,開發者可以使用自己的Executor(也叫做thread pool)接管EventLoops的排程。當netty只作為一個大型軟體系統中作的部分時,這種設計就顯得非常有用。假設一個系統已經在使用高併發處理它的任務,Netty 4.x加入時會簡單的開啟自己的執行緒,而絲毫不顧netty只是這個大型系統的一部分。從netty5.0開始,開發者可以將netty和系統中其它部分放入一個執行緒池中,通過使用更優的排程策略和較少的排程開支來潛在地提高效能。細節變化的討論可以參考GitHub issue 2250

值得一提的是,這個變化並未改變的開發方式。從開發者的視角來看,唯一改變的是,一個ChannelHandler將不再一定會被同一個執行緒一直執行;仍然可保證的是,它不會被多個執行緒同時執行。Netty會負責記憶體可見性的問題,所以不用擔心執行緒安全和ChannelHandlervolatile變數。

更好的Channel.deregister(...)

Netty 4.0引進了Channel.deregister(...),它的行為在5.0版本中被更新用以更符合Netty執行緒模型。

現在可以確保在一個ChannelHandler中提交到EventLoop的所有任務都會在Channel被登出之前被EventLoop執行。然而,Channel.deregister(…)仍然是一個非阻塞的操作,所以我們必須等到ChannelFuture成功返回資料,然後才能安全的把Channel重新註冊到另一個EventLoop上。

在已經呼叫了Channel.deregister(...)後,任何嘗試在ChannelHandler中提交新任務EventLoop的行為將會丟擲異常。只有這個Channel重新註冊到另一個EventLoop後,一切才會恢復正常。

ChannelHandler通過EventLoop.schedule*(...)函式提交的任務會在Channel被登出後停止執行。當這個Channel重新註冊時,任務會自動轉移到新的EventLoop繼續執行。這個限制只會影響那些當Channel被登出時被排程的任務。那些delay或者定時執行的任務不會受到影響。

你可以繞過上面的限制,但我們不推薦這樣做。Netty 5.0引進了一個新函式EventLoop.unwrap(),這個函式可以返回一個原始的EventLoop,這個EventLoop並不執行任何健全性檢查。更準確的講, 當提交任務或者排程任務到 “unwrapped” EventLoop, 不會保證這些任務被併發執行,排程的任務也不保證被自動移到新的EventLoop.