爲什麼說IO密集型業務,線程數是CPU數的2倍?

I/O密集型業務,線程數量要設置成 CPU 的 2 倍!

也不知道這是哪本書的坑爹理論,現在總有一些小青年老拿着這樣的定理來說教。說的信誓旦旦,毋庸置疑,彷彿是權威的化身。討論時把這樣的理論當作前提,真的是受害不淺。

但可惜的是,這樣的理論站不住腳。我只需要一個簡單的反問,它就不攻自破:

Tomcat的默認線程數是多少呢?

它既不是 CPU 的 2 倍,也不是什麼其他數值。在某些高併發的服務中,它的核心線程數,可能達到數千甚至上萬。對於一個Tomcat來說,它處理的大多數都是I/O密集型的業務,可以說是最好的實踐場景。

要明白這個線程數設置的玄機,就必須瞭解I/O請求的特點。I/O請求不僅僅指的是磁盤讀寫,在互聯網服務中更多指的是網絡I/O請求。

I/O請求的速度,要遠低於CPU運行的速度。大部分I/O請求,在發起之後,就進入等待狀態,這個等待狀態不會浪費CPU,所以一臺機器在同一時刻支持的I/O請求,可以很多。

如果I/O請求的速度比較快,和CPU的耗時對等的時候,我們把處理I/O的線程數,設置成 CPU 的 2倍,是合理的。但現實中並沒有這麼多如果,我們要處理秒成千上萬的I/O請求,註定了它的耗時要比CPU多的多。

像RPC組件,比如Dubbo服務端,也會設置一個比較大的線程數(比如600);Feign這種就更不用多說了,短連接意味着更多線程數的支持。這都是些最佳實踐。

雖然I/O線程數量增多,會造成非常頻繁的上下文切換,進而影響效率。但在互聯網應用中,它卻是一個優秀的解決方案。

更優秀的解決方式也有,那就是使用協程。協程是用戶態的線程,是對普通線程更細粒度的劃分。它是在用戶態運行的,由用戶自行調度,所以也就避免了頻繁的上下文切換問題。

但協程在Java中還不成熟,它依然是Golang語言的誘人特性。使用Golang開發的Web服務,可以採用更少的線程來支持大量I/O密集型的請求。

綜上所述,標題的表述並不正確,而且錯的離譜。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章