多线程,多进程选择(了解)
魚還是熊掌:淺談多進(jìn)程多線程的選擇
關(guān)于多進(jìn)程和多線程,教科書上最經(jīng)典的一句話是“進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位”,這句話應(yīng)付考試基本上夠了,但如果在工作中遇到類似的選擇問題,那就沒有這么簡單了,選的不好,會讓你深受其害。
?
經(jīng)常在網(wǎng)絡(luò)上看到有的XDJM問“多進(jìn)程好還是多線程好?”、“Linux下用多進(jìn)程還是多線程?”等等期望一勞永逸的問題,我只能說:沒有最好,只有更好。根據(jù)實(shí)際情況來判斷,哪個更加合適就是哪個好。
?
我們按照多個不同的維度,來看看多線程和多進(jìn)程的對比(注:因?yàn)槭歉行缘谋容^,因此都是相對的,不是說一個好得不得了,另外一個差的無法忍受)。
?
?
| 對比維度 | 多進(jìn)程 | 多線程 | 總結(jié) |
| 數(shù)據(jù)共享、同步 | 數(shù)據(jù)共享復(fù)雜,需要用IPC;數(shù)據(jù)是分開的,同步簡單 | 因?yàn)楣蚕磉M(jìn)程數(shù)據(jù),數(shù)據(jù)共享簡單,但也是因?yàn)檫@個原因?qū)е峦綇?fù)雜 | 各有優(yōu)勢 |
| 內(nèi)存、CPU | 占用內(nèi)存多,切換復(fù)雜,CPU利用率低 | 占用內(nèi)存少,切換簡單,CPU利用率高 | 線程占優(yōu) |
| 創(chuàng)建銷毀、切換 | 創(chuàng)建銷毀、切換復(fù)雜,速度慢 | 創(chuàng)建銷毀、切換簡單,速度很快 | 線程占優(yōu) |
| 編程、調(diào)試 | 編程簡單,調(diào)試簡單 | 編程復(fù)雜,調(diào)試復(fù)雜 | 進(jìn)程占優(yōu) |
| 可靠性 | 進(jìn)程間不會互相影響 | 一個線程掛掉將導(dǎo)致整個進(jìn)程掛掉 | 進(jìn)程占優(yōu) |
| 分布式 | 適應(yīng)于多核、多機(jī)分布式;如果一臺機(jī)器不夠,擴(kuò)展到多臺機(jī)器比較簡單 | 適應(yīng)于多核分布式 | 進(jìn)程占優(yōu) |
?
?
1)需要頻繁創(chuàng)建銷毀的優(yōu)先用線程
原因請看上面的對比。
這種原則最常見的應(yīng)用就是Web服務(wù)器了,來一個連接建立一個線程,斷了就銷毀線程,要是用進(jìn)程,創(chuàng)建和銷毀的代價是很難承受的
2)需要進(jìn)行大量計算的優(yōu)先使用線程
所謂大量計算,當(dāng)然就是要耗費(fèi)很多CPU,切換頻繁了,這種情況下線程是最合適的。
這種原則最常見的是圖像處理、算法處理。
3)強(qiáng)相關(guān)的處理用線程,弱相關(guān)的處理用進(jìn)程
什么叫強(qiáng)相關(guān)、弱相關(guān)?理論上很難定義,給個簡單的例子就明白了。
一般的Server需要完成如下任務(wù):消息收發(fā)、消息處理。“消息收發(fā)”和“消息處理”就是弱相關(guān)的任務(wù),而“消息處理”里面可能又分為“消息解碼”、“業(yè)務(wù)處理”,這兩個任務(wù)相對來說相關(guān)性就要強(qiáng)多了。因此“消息收發(fā)”和“消息處理”可以分進(jìn)程設(shè)計,“消息解碼”、“業(yè)務(wù)處理”可以分線程設(shè)計。
當(dāng)然這種劃分方式不是一成不變的,也可以根據(jù)實(shí)際情況進(jìn)行調(diào)整。
4)可能要擴(kuò)展到多機(jī)分布的用進(jìn)程,多核分布的用線程
原因請看上面對比。
5)都滿足需求的情況下,用你最熟悉、最拿手的方式
至于“數(shù)據(jù)共享、同步”、“編程、調(diào)試”、“可靠性”這幾個維度的所謂的“復(fù)雜、簡單”應(yīng)該怎么取舍,我只能說:沒有明確的選擇方法。但我可以告訴你一個選擇原則:如果多進(jìn)程和多線程都能夠滿足要求,那么選擇你最熟悉、最拿手的那個。?
需要提醒的是:雖然我給了這么多的選擇原則,但實(shí)際應(yīng)用中基本上都是“進(jìn)程+線程”的結(jié)合方式,千萬不要真的陷入一種非此即彼的誤區(qū)。
?
消耗資源:
從內(nèi)核的觀點(diǎn)看,進(jìn)程的目的就是擔(dān)當(dāng)分配系統(tǒng)資源(CPU時間、內(nèi)存等)的基本單位。線程是進(jìn)程的一個執(zhí)行流,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位。
線程,它們彼此之間使用相同的地址空間,共享大部分?jǐn)?shù)據(jù),啟動一個線程所花費(fèi)的空間遠(yuǎn)遠(yuǎn)小于啟動一個進(jìn)程所花費(fèi)的空間,而且,線程間彼此切換所需的時間也遠(yuǎn)遠(yuǎn)小于進(jìn)程間切換所需要的時間。據(jù)統(tǒng)計,總的說來,一個進(jìn)程的開銷大約是一個線程開銷的30倍左右,當(dāng)然,在具體的系統(tǒng)上,這個數(shù)據(jù)可能會有較大的區(qū)別。
通訊方式:
進(jìn)程之間傳遞數(shù)據(jù)只能是通過通訊的方式,即費(fèi)時又不方便。線程時間數(shù)據(jù)大部分共享(線程函數(shù)內(nèi)部不共享),快捷方便。但是數(shù)據(jù)同步需要鎖對于static變量尤其注意
線程自身優(yōu)勢:
提高應(yīng)用程序響應(yīng);使多CPU系統(tǒng)更加有效。操作系統(tǒng)會保證當(dāng)線程數(shù)不大于CPU數(shù)目時,不同的線程運(yùn)行于不同的CPU上;
改善程序結(jié)構(gòu)。一個既長又復(fù)雜的進(jìn)程可以考慮分為多個線程,成為幾個獨(dú)立或半獨(dú)立的運(yùn)行部分,這樣的程序會利于理解和修改。
實(shí)驗(yàn)數(shù)據(jù):
進(jìn)程實(shí)驗(yàn)代碼(fork.c):
進(jìn)程實(shí)驗(yàn)代碼(thread.c):
兩段程序做的事情是一樣的,都是創(chuàng)建“若干”個進(jìn)程/線程,每個創(chuàng)建出的進(jìn)程/線程打印“若干”條“hello linux”字符串到控制臺和日志文件,兩個“若干”由兩個宏 P_NUMBER和COUNT分別定義,程序編譯指令如下:
gcc -o fork fork.c
gcc -lpthread -o thread thread.c
實(shí)驗(yàn)通過time指令執(zhí)行兩個程序,抄錄time輸出的掛鐘時間(real時間):
time ./fork
time ./thread
每批次的實(shí)驗(yàn)通過改動宏 P_NUMBER和COUNT來調(diào)整進(jìn)程/線程數(shù)量和打印次數(shù),每批次測試五輪,得到的結(jié)果如下:
一、重復(fù)周麗論文實(shí)驗(yàn)步驟
(注:本文平均值算法采用的是去掉一個最大值去掉一個最小值,然后平均)
?
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):255,打印次數(shù)5 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?0m0.070s | ?0m0.071s | 0m0.071s? | 0m0.070s? | 0m0.070s? | 0m0.070s? |
| 多線程 | ?0m0.049s | 0m0.049s? | 0m0.049s? | 0m0.049s? | 0m0.049s? | 0m0.049s? |
?
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):255,打印次數(shù)10 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?0m0.112s | 0m0.101s? | 0m0.100s? | 0m0.085s? | 0m0.121s? | 0m0.104s? |
| 多線程 | ?0m0.097s | 0m0.089s? | 0m0.090s? | 0m0.104s? | 0m0.080s? | 0m0.092s? |
?
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):255,打印次數(shù)50 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?0m0.459s | 0m0.531s? | 0m0.499s? | 0m0.499s? | 0m0.524s? | 0m0.507s? |
| 多線程 | ?0m0.387s | 0m0.456s? | 0m0.435s? | 0m0.423s? | 0m0.408s? | 0m0.422s? |
?
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):255,打印次數(shù)100 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?0m1.141s | 0m0.992s? | 0m1.134s? | 0m1.027s? | 0m0.965s? | 0m1.051s? |
| 多線程 | ?0m0.925s | 0m0.899s? | 0m0.961s? | 0m0.934s? | 0m0.853s? | 0m0.919s? |
?
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):255,打印次數(shù)500 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?0m5.221s | 0m5.258s? | 0m5.706s? | 0m5.288s? | 0m5.455s? | 0m5.334s |
| 多線程 | ?0m4.689s | 0m4.578s? | 0m4.670s? | 0m4.566s? | 0m4.722s? | 0m4.646s? |
?
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):255,打印次數(shù)1000 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?0m12.680s | 0m16.555s? | 0m11.158s? | 0m10.922s? | 0m11.206s? | 0m11.681s? |
| 多線程 | ?0m12.993s | 0m13.087s? | 0m13.082s? | 0m13.485s? | 0m13.053s? | 0m13.074s? |
?
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):255,打印次數(shù)5000 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?1m27.348s | 1m5.569s? | 0m57.275s? | 1m5.029s? | 1m15.174s? | 1m8.591s? |
| 多線程 | ?1m25.813s | 1m29.299s | 1m23.842s? | 1m18.914s? | 1m34.872s? | 1m26.318s? |
?
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):255,打印次數(shù)10000 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?2m8.336s | 2m22.999s? | 2m11.046s? | 2m30.040s? | 2m5.752s? | 2m14.137s? |
| 多線程 | ?2m46.666s | 2m44.757s? | 2m34.528s? | 2m15.018s? | 2m41.436s? | 2m40.240s? |
出的結(jié)果是:任務(wù)量較大時,多進(jìn)程比多線程效率高;而完成的任務(wù)量較小時,多線程比多進(jìn)程要快,重復(fù)打印 600 次時,多進(jìn)程與多線程所耗費(fèi)的時間相同。
?
、增加每進(jìn)程/線程的工作強(qiáng)度的實(shí)驗(yàn)
這次將程序打印數(shù)據(jù)增大,原來打印字符串為:
現(xiàn)在修改為每次打印256個字節(jié)數(shù)據(jù):
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):255??,打印次數(shù)100 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?0m6.977s | ?0m7.358s | ?0m7.520s | ?0m7.282s | ?0m7.218s | ?0m7.286 |
| 多線程 | ?0m7.035s | ?0m7.552s | ?0m7.087s | ?0m7.427s | ?0m7.257s | ?0m7.257 |
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):??255,打印次數(shù)500 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?0m35.666s | ?0m36.009s | ?0m36.532s | ?0m35.578s | ?0m41.537s | ?0m36.069 |
| 多線程 | ?0m37.290s | ?0m35.688s | ?0m36.377s | ?0m36.693s | ?0m36.784s | ?0m36.618 |
| 單核(雙核機(jī)器禁掉一核),進(jìn)程/線程數(shù):?255,打印次數(shù)1000 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?1m8.864s | ?1m11.056s | ?1m10.273s | ?1m12.317s | ?1m20.193s | ?1m11.215 |
| 多線程 | ?1m11.949s | ?1m13.088s | ?1m12.291s | ?1m9.677s | ?1m12.210s | ?1m12.150 |
【實(shí)驗(yàn)結(jié)論】
從上面的實(shí)驗(yàn)比對結(jié)果看,即使Linux2.6使用了新的NPTL線程庫(據(jù)說比原線程庫性能提高了很多,唉,又是據(jù)說!),多線程比較多進(jìn)程在效率上沒有任何的優(yōu)勢,在線程數(shù)增大時多線程程序還出現(xiàn)了運(yùn)行錯誤,實(shí)驗(yàn)可以得出下面的結(jié)論:
在Linux2.6上,多線程并不比多進(jìn)程速度快,考慮到線程棧的問題,多進(jìn)程在并發(fā)上有優(yōu)勢。
四、多進(jìn)程和多線程在創(chuàng)建和銷毀上的效率比較
預(yù)先創(chuàng)建進(jìn)程或線程可以節(jié)省進(jìn)程或線程的創(chuàng)建、銷毀時間,在實(shí)際的應(yīng)用中很多程序使用了這樣的策略,比如Apapche預(yù)先創(chuàng)建進(jìn)程、Tomcat 預(yù)先創(chuàng)建線程,通常叫做進(jìn)程池或線程池。在大部分人的概念中,進(jìn)程或線程的創(chuàng)建、銷毀是比較耗時的,在stevesn的著作《Unix網(wǎng)絡(luò)編程》中有這樣 的對比圖(第一卷 第三版 30章 客戶/服務(wù)器程序設(shè)計范式):
?
| 0 | 迭代服務(wù)器(基準(zhǔn)測試,無進(jìn)程控制) | 0.0 | 0.0 | 0.0 |
| 1 | 簡單并發(fā)服務(wù),為每個客戶請求fork一個進(jìn)程 | 504.2 | 168.9 | 29.6 |
| 2 | 預(yù)先派生子進(jìn)程,每個子進(jìn)程調(diào)用accept | ? | 6.2 | 1.8 |
| 3 | 預(yù)先派生子進(jìn)程,用文件鎖保護(hù)accept | 25.2 | 10.0 | 2.7 |
| 4 | 預(yù)先派生子進(jìn)程,用線程互斥鎖保護(hù)accept | 21.5 | ? | ? |
| 5 | 預(yù)先派生子進(jìn)程,由父進(jìn)程向子進(jìn)程傳遞套接字 | 36.7 | 10.9 | 6.1 |
| 6 | 并發(fā)服務(wù),為每個客戶請求創(chuàng)建一個線程 | 18.7 | 4.7 | ? |
| 7 | 預(yù)先創(chuàng)建線程,用互斥鎖保護(hù)accept | 8.6 | 3.5 | ? |
| 8 | 預(yù)先創(chuàng)建線程,由主線程調(diào)用accept | 14.5 | 5.0 | ? |
?
stevens已駕鶴西去多年,但《Unix網(wǎng)絡(luò)編程》一書仍具有巨大的影響力,上表中stevens比較了三種服務(wù)器上多進(jìn)程和多線程的執(zhí)行效 率,因?yàn)槿N服務(wù)器所用計算機(jī)不同,表中數(shù)據(jù)只能縱向比較,而橫向無可比性,stevens在書中提供了這些測試程序的源碼(也可以在網(wǎng)上下載)。書中介 紹了測試環(huán)境,兩臺與服務(wù)器處于同一子網(wǎng)的客戶機(jī),每個客戶并發(fā)5個進(jìn)程(服務(wù)器同一時間最多10個連接),每個客戶請求從服務(wù)器獲取4000字節(jié)數(shù)據(jù), 預(yù)先派生子進(jìn)程或線程的數(shù)量是15個。
第0行是迭代模式的基準(zhǔn)測試程序,服務(wù)器程序只有一個進(jìn)程在運(yùn)行(同一時間只能處理一個客戶請求),因?yàn)闆]有進(jìn)程或線程的調(diào)度切換,因此它的速度是 最快的,表中其他服務(wù)模式的運(yùn)行數(shù)值是比迭代模式多出的差值。迭代模式很少用到,在現(xiàn)有的互聯(lián)網(wǎng)服務(wù)中,DNS、NTP服務(wù)有它的影子。第1~5行是多進(jìn) 程服務(wù)模式,期中第1行使用現(xiàn)場fork子進(jìn)程,2~5行都是預(yù)先創(chuàng)建15個子進(jìn)程模式,在多進(jìn)程程序中套接字傳遞不太容易(相對于多線 程),stevens在這里提供了4個不同的處理accept的方法。6~8行是多線程服務(wù)模式,第6行是現(xiàn)場為客戶請求創(chuàng)建子線程,7~8行是預(yù)先創(chuàng)建 15個線程。表中有的格子是空白的,是因?yàn)檫@個系統(tǒng)不支持此種模式,比如當(dāng)年的BSD不支持線程,因此BSD上多線程的數(shù)據(jù)都是空白的。
從數(shù)據(jù)的比對看,現(xiàn)場為每客戶fork一個進(jìn)程的方式是最慢的,差不多有20倍的速度差異,Solaris上的現(xiàn)場fork和預(yù)先創(chuàng)建子進(jìn)程的最大差別是504.2 :21.5,但我們不能理解為預(yù)先創(chuàng)建模式比現(xiàn)場fork快20倍,原因有兩個:
1. stevens的測試已是十幾年前的了,現(xiàn)在的OS和CPU已起了翻天覆地的變化,表中的數(shù)值需要重新測試。
2. stevens沒有提供服務(wù)器程序整體的運(yùn)行計時,我們無法理解504.2 :21.5的實(shí)際運(yùn)行效率,有可能是1504.2 : 1021.5,也可能是100503.2 : 100021.5,20倍的差異可能很大,也可能可以忽略。
因此我寫了下面的實(shí)驗(yàn)程序,來計算在Linux2.6上創(chuàng)建、銷毀10萬個進(jìn)程/線程的絕對用時。
創(chuàng)建10萬個進(jìn)程(forkcreat.c):
創(chuàng)建10萬個線程(pthreadcreat.c):
創(chuàng)建10萬個線程的Java程序:
?
| 單核(雙核機(jī)器禁掉一核),創(chuàng)建銷毀10萬個進(jìn)程/線程 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均 |
| 多進(jìn)程 | ?0m8.774s | ?0m8.780s | ?0m8.475s | ?0m8.592s | ?0m8.687s | ?0m8.684 |
| 多線程 | ?0m0.663s | ?0m0.660s | ?0m0.662s | ?0m0.660s | ?0m0.661s | ?0m0.661 |
| 12286毫秒 |
?
從數(shù)據(jù)可以看出,多線程比多進(jìn)程在效率上有10多倍的優(yōu)勢,但不能讓我們在使用哪種并發(fā)模式上定性,這讓我想起多年前政治課上的一個場景:在講到優(yōu)越性時,面對著幾個對此發(fā)表質(zhì)疑評論的調(diào)皮男生,我們的政治老師發(fā)表了高見,“不能只橫向地和當(dāng)今的發(fā)達(dá)國家比,你應(yīng)該縱向地和過去中國幾十年的發(fā)展歷史 比”。政治老師的話套用在當(dāng)前簡直就是真理,我們看看,即使是在賽揚(yáng)CPU上,創(chuàng)建、銷毀進(jìn)程/線程的速度都是空前的,可以說是有質(zhì)的飛躍的,平均創(chuàng)建銷毀一個進(jìn)程的速度是0.18毫秒,對于當(dāng)前服務(wù)器幾百、幾千的并發(fā)量,還有預(yù)先派生子進(jìn)程/線程的必要嗎?
預(yù)先派生子進(jìn)程/線程比現(xiàn)場創(chuàng)建子進(jìn)程/線程要復(fù)雜很多,不僅要對池中進(jìn)程/線程數(shù)量進(jìn)行動態(tài)管理,還要解決多進(jìn)程/多線程對accept的“搶” 問題,在stevens的測試程序中,使用了“驚群”和“鎖”技術(shù)。即使stevens的數(shù)據(jù)表格中,預(yù)先派生線程也不見得比現(xiàn)場創(chuàng)建線程快,在 《Unix網(wǎng)絡(luò)編程》第三版中,新作者參照stevens的測試也提供了一組數(shù)據(jù),在這組數(shù)據(jù)中,現(xiàn)場創(chuàng)建線程模式比預(yù)先派生線程模式已有了效率上的優(yōu)勢。因此我對這一節(jié)實(shí)驗(yàn)下的結(jié)論是:
預(yù)先派生進(jìn)程/線程的模式(進(jìn)程池、線程池)技術(shù),不僅復(fù)雜,在效率上也無優(yōu)勢,在新的應(yīng)用中可以放心大膽地為客戶連接請求去現(xiàn)場創(chuàng)建進(jìn)程和線程。
我想,這是fork迷們最愿意看到的結(jié)論了。
五、雙核系統(tǒng)重復(fù)周麗論文實(shí)驗(yàn)步驟
?
| 雙核,進(jìn)程/線程數(shù):255?,打印次數(shù)10 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均(單核倍數(shù)) |
| 多進(jìn)程 | 0m0.061s | 0m0.053s | 0m0.068s | 0m0.061s | 0m0.059s | ?0m0.060(1.73) |
| 多線程 | 0m0.054s | 0m0.040s | 0m0.053s | 0m0.056s | 0m0.042s | ?0m0.050(1.84) |
?
?
?
| 雙核,進(jìn)程/線程數(shù):?255,打印次數(shù)100 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均(單核倍數(shù)) |
| 多進(jìn)程 | 0m0.918s | 0m1.198s | 0m1.241s | 0m1.017s | ?0m1.172s | ?0m1.129(0.93) |
| 多線程 | 0m0.897s | 0m1.166s | 0m1.091s? | 0m1.360s | ?0m0.997s | ?0m1.085(0.85) |
?
?
?
| 雙核,進(jìn)程/線程數(shù):?255,打印次數(shù)1000 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均(單核倍數(shù)) |
| 多進(jìn)程 | 0m11.276s | 0m11.269s? | 0m11.218s | 0m10.919s | 0m11.201s | ?0m11.229(1.04) |
| 多線程 | 0m11.525s | 0m11.984s | 0m11.715s | 0m11.433s | 0m10.966s | ?0m11.558(1.13) |
?
?
| 雙核,進(jìn)程/線程數(shù):255?,打印次數(shù)10000 | ||||||
| ? | 第1次 | 第2次 | 第3次 | 第4次 | 第5次 | 平均(單核倍數(shù)) |
| 多進(jìn)程 | 1m54.328s | 1m54.748s | 1m54.807s | 1m55.950s | 1m57.655s | ?1m55.168(1.16) |
| 多線程 | 2m3.021s | 1m57.611s | 1m59.139s? | 1m58.297s | 1m57.258s? | ?1m58.349(1.35) |
?
【實(shí)驗(yàn)結(jié)論】
雙核處理器在完成任務(wù)量較少時,沒有系統(tǒng)其他瓶頸因素影響時基本上是單核的兩倍,在任務(wù)量較多時,受系統(tǒng)其他瓶頸因素的影響,速度明顯趨近于單核的速度。
六、并發(fā)服務(wù)的不可測性
看到這里,你會感覺到我有挺進(jìn)程、貶線程的論調(diào),實(shí)際上對于現(xiàn)實(shí)中的并發(fā)服務(wù)具有不可測性,前面的實(shí)驗(yàn)和結(jié)論只可做參考,而不可定性。對于不可測性,我舉個生活中的例子。
這幾年在大都市生活的朋友都感覺城市交通狀況越來越差,到處堵車,從好的方面想這不正反應(yīng)了我國GDP的高速發(fā)展。如果你7、8年前來到西安市,穿 過南二環(huán)上的一些十字路口時,會發(fā)現(xiàn)一個奇怪的U型彎的交通管制,為了更好的說明,我畫了兩張圖來說明,第一張圖是采用U型彎之前的,第二張是采用U型彎 之后的。
南二環(huán)交通圖一
南二環(huán)交通圖二
為了講述的方便,我們不考慮十字路口左拐的情況,在圖一中東西向和南北向的車輛交匯在十字路口,用紅綠燈控制同一時間只能東西向或南北向通行,一般 的十字路口都是這樣管控的。隨著車輛的增多,十字路口的堵塞越來越嚴(yán)重,尤其是上下班時間經(jīng)常出現(xiàn)堵死現(xiàn)象。于是交通部門在不動用過多經(jīng)費(fèi)的情況下而采用 了圖二的交通管制,東西向車輛行進(jìn)方式不變,而南北向車輛不能直行,需要右拐到下一個路口拐一個超大的U型彎,這樣的措施避免了因車輛交錯而引發(fā)堵死的次 數(shù),從而提高了車輛的通過效率。我曾經(jīng)問一個每天上下班乘公交經(jīng)過此路口的同事,他說這樣的改動不一定每次上下班時間都能縮短,但上班時間有保障了,從而 遲到次數(shù)減少了。如果今天你去西安市的南二環(huán)已經(jīng)見不到U型彎了,東西向建設(shè)了高架橋,車輛分流后下層的十字路口已恢復(fù)為圖一方式。
從效率的角度分析,在圖一中等一個紅燈45秒,遠(yuǎn)遠(yuǎn)小于圖二拐那個U型彎用去的時間,但實(shí)際情況正好相反。我們可以設(shè)想一下,如果路上的所有運(yùn)行車 輛都是同一型號(比如說全是QQ3微型車),所有的司機(jī)都遵守交規(guī),具有同樣的心情和性格,那么圖一的通行效率肯定比圖二高。現(xiàn)實(shí)中就不一樣了,首先車輛 不統(tǒng)一,有大車、小車、快車、慢車,其次司機(jī)的品行不一,有特別遵守交規(guī)的,有想耍點(diǎn)小聰明的,有性子慢的,也有的性子急,時不時還有三輪摩托逆行一下, 十字路口的“死鎖”也就難免了。
那么在什么情況下圖二優(yōu)于圖一,是否能拿出一個科學(xué)分析數(shù)據(jù)來呢?以現(xiàn)在的科學(xué)技術(shù)水平是拿不出來的,就像長期的天氣預(yù)報不可預(yù)測一樣,西安市的交管部門肯定不是分析各種車輛的運(yùn)行規(guī)律、速度,再進(jìn)行復(fù)雜的社會學(xué)、心理學(xué)分析做出U型彎的決定的,這就是要說的不可測性。
現(xiàn)實(shí)中的程序亦然如此,比如WEB服務(wù)器,有的客戶在快車道(寬帶),有的在慢車道(窄帶),有的性子慢(等待半分鐘也無所謂),有的性子急(拼命 的進(jìn)行瀏覽器刷新),時不時還有一兩個黑客混入其中,這種情況每個服務(wù)器都不一樣,既是是同一服務(wù)器每時每刻的變化也不一樣,因此說不具有可測性。開發(fā)者 和維護(hù)者能做的,不論是前面的這種實(shí)驗(yàn)測試,還是對具體網(wǎng)站進(jìn)行的壓力測試,最多也就能模擬相當(dāng)于QQ3通過十字路口的場景。
結(jié)束語
本篇文章比較了Linux系統(tǒng)上多線程和多進(jìn)程的運(yùn)行效率,在實(shí)際應(yīng)用時還有其他因素的影響,比如網(wǎng)絡(luò)通訊時采用長連接還是短連接,是否采用 select、poll,java中稱為nio的機(jī)制,還有使用的編程語言,例如Java不能使用多進(jìn)程,PHP不能使用多線程,這些都可能影響到并發(fā)模 式的選型。
最后還有兩點(diǎn)提醒:
1. 文章中的所有實(shí)驗(yàn)數(shù)據(jù)有環(huán)境約束。
2. 由于并行服務(wù)的不可測性,文章中的觀點(diǎn)應(yīng)該只做參考,而不要去定性。
?
轉(zhuǎn)載于:https://www.cnblogs.com/zzyoucan/p/3841967.html
總結(jié)
以上是生活随笔為你收集整理的多线程,多进程选择(了解)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机科学综合常用链接
- 下一篇: 定时器Timer