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

杜老師說 2022-01-07 05:03:33 阅读数:18

netty 官方 注意

原文地址  譯者:葉揚V

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

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

變化要點

精簡handler類型繼承關系

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

ChannelInboundHandlerAdapterChannelOutboundHandlerAdapterChannelDuplexHandlerAdapter被弃用然後替換為ChannelHandlerAdapter

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

如果需要更多關於handler繼承關系的變化,請參考the pull request #1999

channelRead0() → messageReceived()

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

更靈活的線程模型

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

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

如果沒有特別指定的話,Executor默認是一個ForkJoinPoolForkJoinPool的特點是使用thread-local隊列。也就是說,一個從線程A提交到ForkJoinPool的任務非常可能再次被線程A執行。這極大的提高了EventLoops的線程關聯性。

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

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

這個改變還有一個影響,NioEventLoop, NioEventLoopGroup, EpollEventLoop and EpollEventLoopGroup都不再使用ThreadFactory對象作為自己的構造函數入參。這些類的構造入參已經昇級為Executor或者ExecutorFactory對象。

更好的Channel.deregister(...)

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

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

在已經調用了Channel.deregister(...)後,任何嘗試在ChannelHandler中提交新任務(Runnable or Callable)EventLoop的行為將會拋出RejectedExecutionException异常。只有這個Channel重新注册到另一個EventLoop後,一切才會恢複正常。

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

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

 

原創文章,轉載請注明: 轉載自並發編程網 – ifeve.com本文鏈接地址: 《Netty官方文檔》5.0中的變化和注意點

FavoriteLoading添加本文到我的收藏
版权声明:本文为[杜老師說]所创,转载请带上原文链接,感谢。 https://gsmany.com/2022/01/202201070503324719.html