1. 程式人生 > 其它 >IO多路複用和執行緒池

IO多路複用和執行緒池

問題本身貌似有問題。簡單比較兩種工具的優劣意義不大。你沒法說錘子和剪刀那個更好。我們一般會評價對於某個場景,哪種工具更合適。

io多路複用(這翻譯真的很坑爹啊),指的是同一個進(線)程可以處理多個IO資料流。

多執行緒

+池模型指的是每個執行緒處理一個IO流。

IO多路複用的優勢在於,當處理的消耗對比IO幾乎可以忽略不計時,可以處理大量的併發IO,而不用消耗太多CPU/記憶體。這就像是一個工作很高效的人,手上一個todo list,他高效的依次處理每個任務。這比每個任務單獨安排一個人要節省(僱人是要發工資的……)。典型的例子是nginx做代理,代理的轉發邏輯相對比較簡單直接,那麼IO多路複用很適合。相反,如果是一個做複雜計算的場景,計算本身可能是個 指數複雜度的東西,IO不是瓶頸。那麼怎麼充分利用CPU或者顯示卡的核心多幹活才是關鍵。

此外,IO多路複用適合處理很多閒置的IO,因為IO socket的數量的增加並不會帶來進(線)程數的增加,也就不會帶來stack記憶體

,核心物件,切換時間的損耗。因此像長連結做通知的場景非常適合。

IO多路複用 + 單進(線)程有個額外的好處,就不會有併發程式設計的各種坑問題,比如在nginx裡,redis裡,程式設計實現都會很簡單很多。程式設計中處理併發衝突和一致性,原子性問題真的是很難,極易出錯。

但是現實中,也有IO多路複用 + 多worker執行緒
的做法,這樣上面這個好處就沒有了。

如果做不到“處理過程相對於IO可以忽略不計”,IO多路複用的並不一定比執行緒池方案更好。比如一個web的服務,用jetty 9的NIO connector,後邊是spring svc + JDBC連線資料庫。spring svc + JDBC連線資料庫這兩塊的處理延遲相對於NIO來說不能忽略,所以並不能指望用jetty 9的NIO connector換了之前的BIO connector的容器,效能能高不少(實際上應該會高一些,但不會太誇張,畢竟瓶頸在後邊處理和DB上)。

順便提一句,Java世界裡,因為JDBC這個東西是BIO的,所以在我們常見的Java服務裡沒有辦法做到全部NIO化,必須得弄成多執行緒模型。如果要在做Java web服務這個大場景下享受IO多路複用的好處,要不就是不需要DB的,要不就是得用Vert.X一類的純NIO框架把DB IO訪問也得框進來。

最後,如果IO壓力過大,一個高併發的東西和一個不那麼高併發的東西,都不能正確響應,對使用者來說是一樣的——就是不能用。假如IO非常的繁重,沒有空閒的連線,那麼IO的壓力在兩種模型下表現差不多,IO多路複用的“併發“看了起來會大一些,但因為IO已經滿了,所以表現出超時嚴重;而執行緒池可能表現為,所有的執行緒都因為IO過慢而卡死了,執行緒池耗盡,新的請求進不來直接報錯。但不管哪一種,在極端壓力下,都無法正常工作。這時,要想著怎麼擴容。

簡單總結一下,

  • 如果壓力不是很大,並且處理效能相對於IO可以忽略不計
    • IO多路複用+單進(線)程比較省資源
    • 適合處理大量的閒置的IO
    • IO多路複用+多單進(線)程與執行緒池方案相比有好處,但是並不會有太大的優勢
  • 如果壓力很大,什麼方案都得跪,這時就得擴容。當然因為IO多路複用+單進(線)程比較省資源,所以擴容時能省錢。

你可以瞭解下飛機塔臺的的工作方式。一個飛空員手上會有很多個航班的牌子。一個人同時管多個牌子,而不是一個人就管1個牌子。如果不能感受到的話,可以看看ACI擴充套件下知識。

轉自:https://www.zhihu.com/question/306267779/answer/570147888