客戶端發(fā)送多條 HTTP 請(qǐng)求用多線程會(huì)比單線程快嗎几莽?

本文想從一個(gè)角度來(lái)讓大家認(rèn)識(shí)到回答一個(gè)問(wèn)題不能從表面或者感覺(jué)來(lái)判斷迅办,這是學(xué)習(xí)技術(shù)的大忌,很多新手如果剛開(kāi)始沒(méi)有一套學(xué)習(xí)方法章蚣,從各種碎片化信息去學(xué)習(xí)編程站欺,學(xué)習(xí)一段時(shí)間很容易進(jìn)入瓶頸期,所以我覺(jué)得有必要通過(guò)一些我平時(shí)思考過(guò)的問(wèn)題纤垂,踩過(guò)得坑矾策,來(lái)總結(jié)一下也方便自己日后鞏固,另一方面也想分享出來(lái)幫助需要的人洒忧,讓大家發(fā)現(xiàn)解決一個(gè)問(wèn)題只有知道背后越多的概念和設(shè)計(jì)蝴韭,思路才會(huì)越多够颠,才會(huì)懂得基礎(chǔ)的重要性熙侍,如果有幸能引發(fā)共鳴和思考,就非常幸運(yùn)了,當(dāng)然文中大部份的內(nèi)容都是我自己內(nèi)化過(guò)之后用淺顯的語(yǔ)言描述蛉抓,盡量讓更多的人能聽(tīng)懂庆尘,不會(huì)像很多博客復(fù)制粘貼,我覺(jué)得也沒(méi)有意義巷送,如果有哪些地方?jīng)]有講清楚驶忌,也歡迎大家交流補(bǔ)充。

首先從問(wèn)題當(dāng)中有幾個(gè)重要的關(guān)鍵詞笑跛,請(qǐng)求付魔,線程,多飞蹂,單几苍,快。我們一個(gè)一個(gè)來(lái)稍為補(bǔ)充一下:

1. 請(qǐng)求陈哑。在題目上下文里指的是客戶端發(fā)送多條HTTP請(qǐng)求到服務(wù)端妻坝。假設(shè)是發(fā)送到同一個(gè)服務(wù)器, 都是HTTP1.1 以上協(xié)議開(kāi)啟了多路復(fù)用的情況惊窖。那就是一條TCP鏈接刽宪。? ? ?

2. 線程。一般客戶端發(fā)送HTTP會(huì)啟一個(gè)單獨(dú)線程界酒,不在主線程渲染UI線程發(fā)起圣拄。? ?

3. 多。就是開(kāi)多個(gè)單獨(dú)線程分別去請(qǐng)求盾计。這里的多的目的是建立多個(gè)TCP還是多個(gè)操作系統(tǒng)的線程售担。? ??

4. 單。就是單獨(dú)一個(gè)操作系統(tǒng)中的線程署辉,自然TCP鏈接就是一個(gè)族铆。? ? ? ?

5. 快。從題目來(lái)看應(yīng)該是想更快接收到所有請(qǐng)求返回給上層業(yè)務(wù)處理哭尝,想讓CPU更快處理完哥攘?還是期望客戶端和服務(wù)器傳輸?shù)臅r(shí)間盡量快?

基于以上拆分出來(lái)的一些小問(wèn)題我們需要了解一些以下的幾個(gè)概念:

CPU計(jì)算密集型:邏輯很復(fù)雜材鹦,非常多的計(jì)算量逝淹,讓CPU幾乎跑滿了,還覺(jué)得達(dá)不到預(yù)期的速度桶唐。

I/O密集型:一直在等待一些外部設(shè)備的輸入或者輸出栅葡,一般速度更CPU關(guān)系不大,比如等待請(qǐng)求返回或者發(fā)送尤泽,等待硬盤(pán)的讀入或者寫(xiě)入等等欣簇。

一规脸、進(jìn)程/線程/協(xié)程

首先需要知道的概念就是進(jìn)程,進(jìn)程是操作系統(tǒng)調(diào)度資源的單位熊咽,怎么理解呢莫鸭?就是一種資源分配隔離機(jī)制,不同進(jìn)程當(dāng)然不能隨意互向修改對(duì)方資源横殴,本著公平的原則被因,由操作系統(tǒng)同一分配安排,當(dāng)然在任一刻的時(shí)候CPU只可能在執(zhí)行一個(gè)進(jìn)程中衫仑,不能同時(shí)在執(zhí)行兩個(gè)進(jìn)程梨与,一般我們開(kāi)發(fā)的App等都是一個(gè)進(jìn)程,那為什么可以同時(shí)聽(tīng)著別的音樂(lè)App的音樂(lè)文狱,看著另外一個(gè)App內(nèi)的文章呢蛋欣,不是同時(shí)進(jìn)行的嗎?

你以為你以為的同時(shí)就是同時(shí)嗎如贷?

你的大腦欺騙了你陷虎,只要CPU在多個(gè)進(jìn)程間切換的足夠快,每個(gè)進(jìn)程只給一點(diǎn)點(diǎn)時(shí)間杠袱,這個(gè)時(shí)間差小到你都感覺(jué)不到尚猿,你就覺(jué)得你的這個(gè)App一直是獨(dú)占了CPU,從沒(méi)離開(kāi)過(guò)你這個(gè)App楣富, 這個(gè)跟我們看視頻看動(dòng)畫(huà)一樣的道理凿掂,圖片切換的足夠快你就認(rèn)為那個(gè)是運(yùn)動(dòng)的動(dòng)態(tài)的,非一些離散的時(shí)間點(diǎn)拼湊的纹蝴。

接下來(lái)要說(shuō)的是線程庄萎,為什么要有線程這個(gè)概念,理論上操作系統(tǒng)的分時(shí)機(jī)制來(lái)快速切換多個(gè)進(jìn)程讓大家都有機(jī)會(huì)被CPU執(zhí)行已經(jīng)很完美了塘安,那就要從單個(gè)進(jìn)程內(nèi)部來(lái)看糠涛,大部分客戶端都會(huì)有一個(gè)主線程,然后耗時(shí)I_O等會(huì)放到其他線程兼犯,為什么這么做呢忍捡,其一渲染在一個(gè)線程來(lái)做簡(jiǎn)單,多線程會(huì)有數(shù)據(jù)競(jìng)爭(zhēng)的問(wèn)題切黔,其二如果都在主線程如果某個(gè)I_O時(shí)間等待太長(zhǎng)一直占住就沒(méi)有機(jī)會(huì)給UI線程渲染就會(huì)體驗(yàn)比較差砸脊,所以大部分的情況跑在主線程UI線程會(huì)讓體驗(yàn)更好,這么來(lái)看在客戶端大部分情況多線程的目的是為了I/O的等待纬霞,當(dāng)然還有一種就是計(jì)算量太大開(kāi)個(gè)線程跑凌埂,是為了利用多核,我們這里暫且討論單核诗芜。

最后是協(xié)程瞳抓∶虢簦可能寫(xiě)客戶端的接觸協(xié)程應(yīng)該還比較少,Kotlin就有協(xié)程挨下,當(dāng)然很多語(yǔ)言都有協(xié)程,為什么又要搞出個(gè)這個(gè)東西呢脐湾,多線程還不能滿足嗎臭笆,多線程一般為了I/O的時(shí)候不阻塞當(dāng)前線程而開(kāi)啟了多個(gè)線程,但是線程的創(chuàng)建需要大概1M的資源秤掌,所以不能創(chuàng)建太多愁铺,其二多線程切換切換也有成本,需要保存上下文值闻鉴,所以協(xié)程就是一種更輕量的執(zhí)行任務(wù)的單元茵乱,協(xié)程和線程區(qū)別是:協(xié)程一般由編程語(yǔ)言的內(nèi)部實(shí)現(xiàn),由可以控制的調(diào)度器去控制切換孟岛,而線程雖然也可以控制當(dāng)前所在線程瓶竭,但是線程所屬的進(jìn)程由操作系統(tǒng)搶占式的切換。協(xié)程屬于輕量級(jí)線程渠羞,一般背后可以有1對(duì)1或者M(jìn)對(duì)N或者N對(duì)1的真實(shí)線程斤贰,不同語(yǔ)言實(shí)現(xiàn)不一樣。例如Python的協(xié)程是N對(duì)1次询,Golang的goroutine是M對(duì)N荧恍。

二、為什么要用多進(jìn)程/線程/協(xié)程

上面主要介紹了客戶端會(huì)使用多線程的情況屯吊,客戶端一般不會(huì)用到多進(jìn)程送巡,當(dāng)然也可以,多進(jìn)程的使用一般都為了利用多核去處理計(jì)算密集型盒卸,多核可以看成多臺(tái)計(jì)算機(jī)一起運(yùn)算骗爆,再說(shuō)說(shuō)服務(wù)端為什么要用多進(jìn)程或者多線程呢?如果是單進(jìn)程的話蔽介,我們寫(xiě)的服務(wù)端代碼放在服務(wù)器淮腾,當(dāng)有一個(gè)用戶請(qǐng)求進(jìn)來(lái)需要處理至少需要一個(gè)進(jìn)程,此時(shí)如果沒(méi)有處理完又來(lái)了一個(gè)用戶請(qǐng)求需要處理屉佳,此時(shí)如果還是單進(jìn)程就需要排隊(duì)了谷朝,那么這個(gè)并發(fā)量大的時(shí)候顯然我們是不能接受的,所以此時(shí)我們可以用單進(jìn)程的方式武花,但是用多線程每個(gè)用戶對(duì)應(yīng)一個(gè)線程去處理圆凰,我們上面知道線程是比較重的,而且開(kāi)的線程數(shù)量也有限因?yàn)橘Y源是有限的体箕,一般服務(wù)端會(huì)用線程池的方式prefork就是預(yù)先創(chuàng)建一堆線程专钉。所以只是一種不太好的方案挑童,多進(jìn)程的方案嘛也可以,跟上面一樣只是更加占用資源了跃须,prefork的方式是不錯(cuò)站叼,但是有個(gè)缺陷是并發(fā)量不大的時(shí)候也要預(yù)先創(chuàng)建一堆線程,俗話就是站著坑不拉屎菇民,而協(xié)程的創(chuàng)建幾乎不占用多少資源尽楔,可以隨時(shí)用隨時(shí)釋放,所以現(xiàn)在一些高性能web服務(wù)器都采用這種方案第练。就不舉例子了阔馋。

三、發(fā)送請(qǐng)求背后發(fā)生了什么

終于到了網(wǎng)絡(luò)部分娇掏,我們知道TCP鏈接的建立需要三次握手呕寝,其中一部分的原因就是因?yàn)樾枰p方共識(shí)大家初始化的id來(lái)標(biāo)識(shí)每次請(qǐng)求的id,什么是建立連接婴梧?拿一跟線兩頭連接上嗎下梢?當(dāng)然不是,連接的本質(zhì)是雙方各自初始化了一個(gè)socket的標(biāo)識(shí)符塞蹭,可以當(dāng)成一個(gè)文件怔球,以后這個(gè)連接發(fā)送過(guò)來(lái)的東西都存到這個(gè)里面,所以說(shuō)連接只是讓雙方確認(rèn)一下浮还,認(rèn)識(shí)到以后有數(shù)據(jù)進(jìn)來(lái)可以識(shí)別出來(lái)竟坛。發(fā)送請(qǐng)求其實(shí)就是先把要發(fā)送的數(shù)據(jù)存到一個(gè)緩沖區(qū),然后等待操作系統(tǒng)幫你一層層打包發(fā)送到網(wǎng)卡然后走網(wǎng)線出去而已钧舌,接受就是一個(gè)相反的過(guò)程本質(zhì)是一樣的担汤。所以我們打包的過(guò)程其實(shí)是很快的,接受也是洼冻,慢是慢在這個(gè)路程中崭歧,跟快遞一樣,所以就算開(kāi)了多個(gè)操作系統(tǒng)的線程并不會(huì)加快多少速度撞牢,開(kāi)多個(gè)TCP的鏈接呢率碾,理論上會(huì)快,跟多線程下載是一個(gè)原因屋彪,快的是你想占用服務(wù)器更多的帶寬所宰,對(duì)于服務(wù)端來(lái)說(shuō)帶寬一定,他需要公平的對(duì)待多條TCP鏈接畜挥,所以當(dāng)然你占用條數(shù)越多速度也相對(duì)會(huì)快一點(diǎn)仔粥,這里面還有很多細(xì)節(jié)會(huì)影響速度,客戶端的帶寬,客戶端的TCP鏈接數(shù)躯泰,TCP擁塞控制等等谭羔,讀者們可以去擴(kuò)展閱讀,本文能達(dá)到啟蒙或者有那么點(diǎn)意思就夠了麦向。

總結(jié):

經(jīng)過(guò)上面我們的分析我們可以發(fā)現(xiàn)瘟裸,回答一個(gè)問(wèn)題可能并沒(méi)有銀彈,需要有一個(gè)場(chǎng)景一個(gè)上下文诵竭,一個(gè)具體的業(yè)務(wù)中我們?cè)龠\(yùn)用這些基礎(chǔ)的知識(shí)去深入思考话告,來(lái)給我們程序設(shè)計(jì)或者調(diào)優(yōu)。所以說(shuō)努力一定就會(huì)成功嗎秀撇?如果遇到一定這個(gè)詞,我們需要的是多個(gè)角度向族,多個(gè)維度來(lái)去看待問(wèn)題呵燕,給出我們認(rèn)為的一種思路,而不是想當(dāng)然件相,感謝你認(rèn)真的讀完再扭,這是我第一次嘗試用自己的語(yǔ)言去解釋一些編程中的問(wèn)題,如果你覺(jué)得還不錯(cuò)或者哪里不太好的地方歡迎給我留言夜矗,也許就是你的留言才讓我堅(jiān)持下去?

如需轉(zhuǎn)載請(qǐng)聯(lián)系本人泛范,標(biāo)注轉(zhuǎn)發(fā)自原始地址。想要關(guān)注更多博主文章請(qǐng)關(guān)注公眾號(hào)紊撕,也可以訪問(wèn)博客地址:Blog[1]

References

[1]?Blog:?koofrank.com

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末罢荡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子对扶,更是在濱河造成了極大的恐慌区赵,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件浪南,死亡現(xiàn)場(chǎng)離奇詭異笼才,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)络凿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)骡送,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人絮记,你說(shuō)我怎么就攤上這事摔踱。” “怎么了怨愤?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵昌渤,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我憔四,道長(zhǎng)膀息,這世上最難降的妖魔是什么般眉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮潜支,結(jié)果婚禮上甸赃,老公的妹妹穿的比我還像新娘。我一直安慰自己冗酿,他們只是感情好埠对,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著裁替,像睡著了一般项玛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上弱判,一...
    開(kāi)封第一講書(shū)人閱讀 51,274評(píng)論 1 300
  • 那天襟沮,我揣著相機(jī)與錄音,去河邊找鬼昌腰。 笑死开伏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的遭商。 我是一名探鬼主播固灵,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼劫流!你這毒婦竟也來(lái)了巫玻?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤祠汇,失蹤者是張志新(化名)和其女友劉穎大审,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體座哩,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡徒扶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了根穷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姜骡。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖屿良,靈堂內(nèi)的尸體忽然破棺而出圈澈,到底是詐尸還是另有隱情,我是刑警寧澤尘惧,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布康栈,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏啥么。R本人自食惡果不足惜登舞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望悬荣。 院中可真熱鬧菠秒,春花似錦、人聲如沸氯迂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嚼蚀。三九已至禁灼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轿曙,已是汗流浹背弄捕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拳芙,地道東北人察藐。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓皮璧,卻偏偏與公主長(zhǎng)得像舟扎,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子悴务,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354