前端的请求最大线程数是多少啊_面试官:创建多少个线程合适,我该怎么说?...
轉(zhuǎn)載:https://mp.weixin.qq.com/s/j5d4Jtxo0RgJWgpnG9HxlQ
為什么要使用多線程?
防止并發(fā)編程出錯(cuò)最好的辦法就是不寫并發(fā)程序
既然多線程編程容易出錯(cuò),為什么它還經(jīng)久不衰呢?
A:那還用說,肯定在某些方面有特長唄,比如你知道的【它很快,非常快】
我也很贊同這個(gè)答案,但說的不夠具體
并發(fā)編程適用于什么場景?
如果問你選擇多線程的原因就是一個(gè)【快】字,面試也就不會(huì)出那么多幺蛾子了。你有沒有問過你自己
想知道這兩個(gè)問題的答案,我們需要一個(gè)從【定性】到【定量】的分析過程
使用多線程就是在正確的場景下通過設(shè)置正確個(gè)數(shù)的線程來最大化程序的運(yùn)行速度(我感覺你還是啥也沒說)
將這句話翻譯到硬件級(jí)別就是要充分的利用 CPU 和 I/O 的利用率
兩個(gè)正確得到保證,也就能達(dá)到最大化利用 CPU 和 I/O的目的了。最關(guān)鍵是,如何做到兩個(gè)【正確】?
在聊具體場景的時(shí)候,我們必須要拿出我們的專業(yè)性來。送你兩個(gè)名詞 buff 加成
- CPU 密集型程序
- I/O 密集型程序
CPU 密集型程序
一個(gè)完整請(qǐng)求,I/O操作可以在很短時(shí)間內(nèi)完成, CPU還有很多運(yùn)算要處理,也就是說 CPU 計(jì)算的比例占很大一部分
假如我們要計(jì)算 1+2+....100億 的總和,很明顯,這就是一個(gè) CPU 密集型程序
在【單核】CPU下,如果我們創(chuàng)建 4 個(gè)線程來分段計(jì)算,即:
我們來看下圖他們會(huì)發(fā)生什么?
由于是單核 CPU,所有線程都在等待 CPU 時(shí)間片。按照理想情況來看,四個(gè)線程執(zhí)行的時(shí)間總和與一個(gè)線程5獨(dú)自完成是相等的,實(shí)際上我們還忽略了四個(gè)線程上下文切換的開銷
所以,單核CPU處理CPU密集型程序,這種情況并不太適合使用多線程
此時(shí)如果在 4 核CPU下,同樣創(chuàng)建四個(gè)線程來分段計(jì)算,看看會(huì)發(fā)生什么?
每個(gè)線程都有 CPU 來運(yùn)行,并不會(huì)發(fā)生等待 CPU 時(shí)間片的情況,也沒有線程切換的開銷。理論情況來看效率提升了 4 倍
所以,如果是多核CPU 處理 CPU 密集型程序,我們完全可以最大化的利用 CPU 核心數(shù),應(yīng)用并發(fā)編程來提高效率
I/O密集型程序
與 CPU 密集型程序相對(duì),一個(gè)完整請(qǐng)求,CPU運(yùn)算操作完成之后還有很多 I/O 操作要做,也就是說 I/O 操作占比很大部分
我們都知道在進(jìn)行 I/O 操作時(shí),CPU是空閑狀態(tài),所以我們要最大化的利用 CPU,不能讓其是空閑狀態(tài)
同樣在單核 CPU 的情況下:
從上圖中可以看出,每個(gè)線程都執(zhí)行了相同長度的 CPU 耗時(shí)和 I/O 耗時(shí),如果你將上面的圖多畫幾個(gè)周期,CPU操作耗時(shí)固定,將 I/O 操作耗時(shí)變?yōu)?CPU 耗時(shí)的 3 倍,你會(huì)發(fā)現(xiàn),CPU又有空閑了,這時(shí)你就可以新建線程 4,來繼續(xù)最大化的利用 CPU。
綜上兩種情況我們可以做出這樣的總結(jié):
線程等待時(shí)間所占比例越高,需要越多線程;線程CPU時(shí)間所占比例越高,需要越少線程。
到這里,相信你已經(jīng)知道第一個(gè)【正確】使用多線程的場景了,那創(chuàng)建多少個(gè)線程是正確的呢?
創(chuàng)建多少個(gè)線程合適?
面試如果問到這個(gè)問題,這可是對(duì)你理論和實(shí)踐的統(tǒng)考。想完全答對(duì),你必須要【精通/精通/精通】小學(xué)算術(shù)
從上面知道,我們有 CPU 密集型和 I/O 密集型兩個(gè)場景,不同的場景當(dāng)然需要的線程數(shù)也就不一樣了
CPU 密集型程序創(chuàng)建多少個(gè)線程合適?
有些同學(xué)早已經(jīng)發(fā)現(xiàn),對(duì)于 CPU 密集型來說,理論上 線程數(shù)量 = CPU 核數(shù)(邏輯) 就可以了,但是實(shí)際上,數(shù)量一般會(huì)設(shè)置為 CPU 核數(shù)(邏輯)+ 1, 為什么呢?
《Java并發(fā)編程實(shí)戰(zhàn)》這么說:
計(jì)算密(CPU)集型的線程恰好在某時(shí)因?yàn)榘l(fā)生一個(gè)頁錯(cuò)誤或者因其他原因而暫停,剛好有一個(gè)“額外”的線程,可以確保在這種情況下CPU周期不會(huì)中斷工作。
所以對(duì)于CPU密集型程序, CPU 核數(shù)(邏輯)+ 1 個(gè)線程數(shù)是比較好的經(jīng)驗(yàn)值的原因了
I/O密集型程序創(chuàng)建多少個(gè)線程合適?
上面已經(jīng)讓大家按照?qǐng)D多畫幾個(gè)周期(你可以動(dòng)手將I/O耗時(shí)與CPU耗時(shí)比例調(diào)大,比如6倍或7倍),這樣你就會(huì)得到一個(gè)結(jié)論,對(duì)于 I/O 密集型程序:
最佳線程數(shù) = (1/CPU利用率) = 1 + (I/O耗時(shí)/CPU耗時(shí))
我這么體貼,當(dāng)然擔(dān)心有些同學(xué)不理解這個(gè)公式,我們將上圖的比例手動(dòng)帶入到上面的公式中:
這是一個(gè)CPU核心的最佳線程數(shù),如果多個(gè)核心,那么 I/O 密集型程序的最佳線程數(shù)就是:
最佳線程數(shù) = CPU核心數(shù) * (1/CPU利用率) = CPU核心數(shù) * 1 + (I/O耗時(shí)/CPU耗時(shí))
說到這,有些同學(xué)可能有疑問了,要計(jì)算 I/O 密集型程序,是要知道 CPU 利用率的,如果我不知道這些,那要怎樣給出一個(gè)初始值呢?
按照上面公式,假如幾乎全是 I/O耗時(shí),所以純理論你就可以說是2N(N=CPU核數(shù)),當(dāng)然也有說 2N + 1的,(我猜這個(gè) 1 也是 backup),沒有找到具體的推倒過程,在【并發(fā)編程實(shí)戰(zhàn)-8.2章節(jié)】截圖在此,大家有興趣的可以自己看看
理論上來說,理論上來說,理論上來說,這樣就能達(dá)到 CPU 100% 的利用率
如果理論都好用,那就用不著實(shí)踐了,也就更不會(huì)有調(diào)優(yōu)的事出現(xiàn)了。不過在初始階段,我們確實(shí)可以按照這個(gè)理論之作為偽標(biāo)準(zhǔn), 畢竟差也可能不會(huì)差太多,這樣調(diào)優(yōu)也會(huì)更好一些
談完理論,咱們說點(diǎn)實(shí)際的,公式我看懂了(定性階段結(jié)束),但是我有兩個(gè)疑問:
沒錯(cuò),我們需要定量分析了
幸運(yùn)的是,我們并不是第一個(gè)吃螃蟹的仔兒,其實(shí)有很多 APM (Application Performance Manager)工具可以幫我們得到準(zhǔn)確的數(shù)據(jù),學(xué)會(huì)使用這類工具,也就可以結(jié)合理論,在調(diào)優(yōu)的過程得到更優(yōu)的線程個(gè)數(shù)了。我這里簡單列舉幾個(gè),具體使用哪一個(gè),具體應(yīng)用還需要你自己去調(diào)研選擇,受篇幅限制,暫不展開討論了
上面了解了基本的理論知識(shí),那面試有可能問什么?又可能會(huì)以怎樣的方式提問呢?
面試小問
小問一
假設(shè)要求一個(gè)系統(tǒng)的 TPS(Transaction Per Second 或者 Task Per Second)至少為20,然后假設(shè)每個(gè)Transaction由一個(gè)線程完成,繼續(xù)假設(shè)平均每個(gè)線程處理一個(gè)Transaction的時(shí)間為4s
如何設(shè)計(jì)線程個(gè)數(shù),使得可以在1s內(nèi)處理完20個(gè)Transaction?
但是,但是,這是因?yàn)闆]有考慮到CPU數(shù)目。家里又沒礦,一般服務(wù)器的CPU核數(shù)為16或者32,如果有80個(gè)線程,那么肯定會(huì)帶來太多不必要的線程上下文切換開銷(希望這句話你可以主動(dòng)說出來),這就需要調(diào)優(yōu)了,來做到最佳 balance
小問二
計(jì)算操作需要5ms,DB操作需要 100ms,對(duì)于一臺(tái) 8個(gè)CPU的服務(wù)器,怎么設(shè)置線程數(shù)呢?
如果不知道請(qǐng)拿三年級(jí)期末考試題重新做(今天晚自習(xí)留下來),答案是:
線程數(shù) = 8 * (1 + 100/5) = 168 (個(gè))
那如果DB的 QPS(Query Per Second)上限是1000,此時(shí)這個(gè)線程數(shù)又該設(shè)置為多大呢?
同樣,這是沒有考慮 CPU 數(shù)目,接下來就又是細(xì)節(jié)調(diào)優(yōu)的階段了
因?yàn)橐淮握?qǐng)求不僅僅包括 CPU 和 I/O操作,具體的調(diào)優(yōu)過程還要考慮內(nèi)存資源,網(wǎng)絡(luò)等具體內(nèi)容
增加 CPU 核數(shù)一定能解決問題嗎?
看到這,有些同學(xué)可能會(huì)認(rèn)為,即便我算出了理論線程數(shù),但實(shí)際CPU核數(shù)不夠,會(huì)帶來線程上下文切換的開銷,所以下一步就需要增加 CPU 核數(shù),那我們盲目的增加 CPU 核數(shù)就一定能解決問題嗎?
在講互斥鎖的內(nèi)容是,我故意遺留了一個(gè)知識(shí):
怎么理解這個(gè)公式呢?
這個(gè)結(jié)論告訴我們,假如我們的串行率是 5%,那么我們無論采用什么技術(shù),最高也就只能提高 20 倍的性能。
如何簡單粗暴的理解串行百分比(其實(shí)都可以通過工具得出這個(gè)結(jié)果的)呢?來看個(gè)小 Tips:
Tips: 臨界區(qū)都是串行的,非臨界區(qū)都是并行的,用單線程執(zhí)行臨界區(qū)的時(shí)間/用單線程執(zhí)行(臨界區(qū)+非臨界區(qū))的時(shí)間就是串行百分比
現(xiàn)在你應(yīng)該理解我在講解 synchronized 關(guān)鍵字時(shí)所說的:
最小化臨界區(qū)范圍,因?yàn)榕R界區(qū)的大小往往就是瓶頸問題的所在,不要像亂用try catch那樣一鍋端
總結(jié)
多線程不一定就比但線程高效,比如大名鼎鼎的 Redis (后面會(huì)分析),因?yàn)樗腔趦?nèi)存操作,這種情況下,單線程可以很高效的利用CPU。而多線程的使用場景一般時(shí)存在相當(dāng)比例的I/O或網(wǎng)絡(luò)操作
另外,結(jié)合小學(xué)數(shù)學(xué)題,我們已經(jīng)了解了如何從定性到定量的分析的過程,在開始沒有任何數(shù)據(jù)之前,我們可以使用上文提到的經(jīng)驗(yàn)值作為一個(gè)偽標(biāo)準(zhǔn),其次就是結(jié)合實(shí)際來逐步的調(diào)優(yōu)(綜合 CPU,內(nèi)存,硬盤讀寫速度,網(wǎng)絡(luò)狀況等)了
最后,盲目的增加 CPU 核數(shù)也不一定能解決我們的問題,這就要求我們嚴(yán)格的編寫并發(fā)程序代碼了
靈魂追問
總結(jié)
以上是生活随笔為你收集整理的前端的请求最大线程数是多少啊_面试官:创建多少个线程合适,我该怎么说?...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为了新中国前进剧情介绍
- 下一篇: 宠物该怎么卖,不想要了