欧美性猛交xxxx免费看_牛牛在线视频国产免费_天堂草原电视剧在线观看免费_国产粉嫩高清在线观看_国产欧美日本亚洲精品一5区

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux系統(tǒng)上多線程和多進(jìn)程的運(yùn)行效率

科技綠洲 ? 來(lái)源:Linux開(kāi)發(fā)架構(gòu)之路 ? 作者:Linux開(kāi)發(fā)架構(gòu)之路 ? 2023-11-10 10:54 ? 次閱讀

關(guān)于多進(jìn)程和多線程,教科書(shū)上最經(jīng)典的一句話是“進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位”,這句話應(yīng)付考試基本上夠了,但如果在工作中遇到類(lèi)似的選擇問(wèn)題,那就沒(méi)有這么簡(jiǎn)單了,選的不好,會(huì)讓你深受其害。

經(jīng)常在網(wǎng)絡(luò)上看到有的XDJM問(wèn)“多進(jìn)程好還是多線程好?”、“Linux下用多進(jìn)程還是多線程?”等等期望一勞永逸的問(wèn)題,我只能說(shuō):沒(méi)有最好,只有更好。根據(jù)實(shí)際情況來(lái)判斷,哪個(gè)更加合適就是哪個(gè)好。

我們按照多個(gè)不同的維度,來(lái)看看多線程和多進(jìn)程的對(duì)比(注:因?yàn)槭歉行缘谋容^,因此都是相對(duì)的,不是說(shuō)一個(gè)好得不得了,另外一個(gè)差的無(wú)法忍受)。

圖片

看起來(lái)比較簡(jiǎn)單,優(yōu)勢(shì)對(duì)比上是“線程 3.5 v 2.5 進(jìn)程”,我們只管選線程就是了?

呵呵,有這么簡(jiǎn)單我就不用在這里浪費(fèi)口舌了,還是那句話,沒(méi)有絕對(duì)的好與壞,只有哪個(gè)更加合適的問(wèn)題。我們來(lái)看實(shí)際應(yīng)用中究竟如何判斷更加合適。

1)需要頻繁創(chuàng)建銷(xiāo)毀的優(yōu)先用線程

原因請(qǐng)看上面的對(duì)比。

這種原則最常見(jiàn)的應(yīng)用就是Web服務(wù)器了,來(lái)一個(gè)連接建立一個(gè)線程,斷了就銷(xiāo)毀線程,要是用進(jìn)程,創(chuàng)建和銷(xiāo)毀的代價(jià)是很難承受的

2)需要進(jìn)行大量計(jì)算的優(yōu)先使用線程

所謂大量計(jì)算,當(dāng)然就是要耗費(fèi)很多CPU,切換頻繁了,這種情況下線程是最合適的。

這種原則最常見(jiàn)的是圖像處理、算法處理。

3)強(qiáng)相關(guān)的處理用線程,弱相關(guān)的處理用進(jìn)程

什么叫強(qiáng)相關(guān)、弱相關(guān)?理論上很難定義,給個(gè)簡(jiǎn)單的例子就明白了。

一般的Server需要完成如下任務(wù):消息收發(fā)、消息處理?!跋⑹瞻l(fā)”和“消息處理”就是弱相關(guān)的任務(wù),而“消息處理”里面可能又分為“消息解碼”、“業(yè)務(wù)處理”,這兩個(gè)任務(wù)相對(duì)來(lái)說(shuō)相關(guān)性就要強(qiáng)多了。因此“消息收發(fā)”和“消息處理”可以分進(jìn)程設(shè)計(jì),“消息解碼”、“業(yè)務(wù)處理”可以分線程設(shè)計(jì)。

當(dāng)然這種劃分方式不是一成不變的,也可以根據(jù)實(shí)際情況進(jìn)行調(diào)整。

4)可能要擴(kuò)展到多機(jī)分布的用進(jìn)程,多核分布的用線程

原因請(qǐng)看上面對(duì)比。

5)都滿足需求的情況下,用你最熟悉、最拿手的方式

至于“數(shù)據(jù)共享、同步”、“編程、調(diào)試”、“可靠性”這幾個(gè)維度的所謂的“復(fù)雜、簡(jiǎn)單”應(yīng)該怎么取舍,我只能說(shuō):沒(méi)有明確的選擇方法。但我可以告訴你一個(gè)選擇原則:如果多進(jìn)程和多線程都能夠滿足要求,那么選擇你最熟悉、最拿手的那個(gè)。

需要提醒的是:雖然我給了這么多的選擇原則,但實(shí)際應(yīng)用中基本上都是“進(jìn)程+線程”的結(jié)合方式,千萬(wàn)不要真的陷入一種非此即彼的誤區(qū)。

1、進(jìn)程與線程

進(jìn)程是程序執(zhí)行時(shí)的一個(gè)實(shí)例,即它是程序已經(jīng)執(zhí)行到課中程度的數(shù)據(jù)結(jié)構(gòu)的匯集。從內(nèi)核的觀點(diǎn)看,進(jìn)程的目的就是擔(dān)當(dāng)分配系統(tǒng)資源(CPU時(shí)間、內(nèi)存等)的基本單位。

線程是進(jìn)程的一個(gè)執(zhí)行流,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位。一個(gè)進(jìn)程由幾個(gè)線程組成(擁有很多相對(duì)獨(dú)立的執(zhí)行流的用戶程序共享應(yīng)用程序的大部分?jǐn)?shù)據(jù)結(jié)構(gòu)),線程與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源。

"進(jìn)程——資源分配的最小單位,線程——程序執(zhí)行的最小單位"

進(jìn)程有獨(dú)立的地址空間,一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對(duì)其它進(jìn)程產(chǎn)生影響,而線程只是一個(gè)進(jìn)程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程沒(méi)有單獨(dú)的地址空間,一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉,所以多進(jìn)程的程序要比多線程的程序健壯,但在進(jìn)程切換時(shí),耗費(fèi)資源較大,效率要差一些。但對(duì)于一些要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進(jìn)程。

總的來(lái)說(shuō)就是:進(jìn)程有獨(dú)立的地址空間,線程沒(méi)有單獨(dú)的地址空間(同一進(jìn)程內(nèi)的線程共享進(jìn)程的地址空間)。

使用多線程的理由之一是和進(jìn)程相比,它是一種非常"節(jié)儉"的多任務(wù)操作方式。我們知道,在Linux系統(tǒng)下,啟動(dòng)一個(gè)新的進(jìn)程必須分配給它獨(dú)立的地址空間,建立眾多的數(shù)據(jù)表來(lái)維護(hù)它的代碼段、堆棧段和數(shù)據(jù)段,這是一種"昂貴"的多任務(wù)工作方式。而運(yùn)行于一個(gè)進(jìn)程中的多個(gè)線程,它們彼此之間使用相同的地址空間,共享大部分?jǐn)?shù)據(jù),啟動(dòng)一個(gè)線程所花費(fèi)的空間遠(yuǎn)遠(yuǎn)小于啟動(dòng)一個(gè)進(jìn)程所花費(fèi)的空間,而且,線程間彼此切換所需的時(shí)間也遠(yuǎn)遠(yuǎn)小于進(jìn)程間切換所需要的時(shí)間。據(jù)統(tǒng)計(jì),總的說(shuō)來(lái),一個(gè)進(jìn)程的開(kāi)銷(xiāo)大約是一個(gè)線程開(kāi)銷(xiāo)的30倍左右,當(dāng)然,在具體的系統(tǒng)上,這個(gè)數(shù)據(jù)可能會(huì)有較大的區(qū)別。

使用多線程的理由之二是線程間方便的通信機(jī)制。對(duì)不同進(jìn)程來(lái)說(shuō),它們具有獨(dú)立的數(shù)據(jù)空間,要進(jìn)行數(shù)據(jù)的傳遞只能通過(guò)通信的方式進(jìn)行,這種方式不僅費(fèi)時(shí),而且很不方便。線程則不然,由于同一進(jìn)程下的線程之間共享數(shù)據(jù)空間,所以一個(gè)線程的數(shù)據(jù)可以直接為其它線程所用,這不僅快捷,而且方便。當(dāng)然,數(shù)據(jù)的共享也帶來(lái)其他一些問(wèn)題,有的變量不能同時(shí)被兩個(gè)線程所修改,有的子程序中聲明為static的數(shù)據(jù)更有可能給多線程程序帶來(lái)災(zāi)難性的打擊,這些正是編寫(xiě)多線程程序時(shí)最需要注意的地方。

除了以上所說(shuō)的優(yōu)點(diǎn)外,不和進(jìn)程比較,多線程程序作為一種多任務(wù)、并發(fā)的工作方式,當(dāng)然有以下的優(yōu)點(diǎn):

  • 提高應(yīng)用程序響應(yīng)。這對(duì)圖形界面的程序尤其有意義,當(dāng)一個(gè)操作耗時(shí)很長(zhǎng)時(shí),整個(gè)系統(tǒng)都會(huì)等待這個(gè)操作,此時(shí)程序不會(huì)響應(yīng)鍵盤(pán)、鼠標(biāo)、菜單的操作,而使用多線程技術(shù),將耗時(shí)長(zhǎng)的操作(time consuming)置于一個(gè)新的線程,可以避免這種尷尬的情況。
  • 使多CPU系統(tǒng)更加有效。操作系統(tǒng)會(huì)保證當(dāng)線程數(shù)不大于CPU數(shù)目時(shí),不同的線程運(yùn)行于不同的CPU上。
  • 改善程序結(jié)構(gòu)。一個(gè)既長(zhǎng)又復(fù)雜的進(jìn)程可以考慮分為多個(gè)線程,成為幾個(gè)獨(dú)立或半獨(dú)立的運(yùn)行部分,這樣的程序會(huì)利于理解和修改。

在linux上編程采用多線程還是多進(jìn)程的爭(zhēng)執(zhí)由來(lái)已久,這種爭(zhēng)執(zhí)最常見(jiàn)到在B/S通訊中服務(wù)端并發(fā)技術(shù) 的選型上,比如WEB服務(wù)器技術(shù)中,Apache是采用多進(jìn)程的(perfork模式,每客戶連接對(duì)應(yīng)一個(gè)進(jìn)程,每進(jìn)程中只存在唯一一個(gè)執(zhí)行線 程)。

從Unix發(fā)展歷史看,伴隨著Unix的誕生多進(jìn)程就出現(xiàn)了,而多線程很晚才被系統(tǒng)支持,例如Linux直到內(nèi)核2.6,才支持符合Posix規(guī)范的NPTL線程庫(kù)。進(jìn)程和線程的特點(diǎn),也就是各自的優(yōu)缺點(diǎn)如下:

進(jìn)程優(yōu)點(diǎn):編程、調(diào)試簡(jiǎn)單,可靠性較高。進(jìn)程缺點(diǎn):創(chuàng)建、銷(xiāo)毀、切換速度慢,內(nèi)存、資源占用大。線程優(yōu)點(diǎn):創(chuàng)建、銷(xiāo)毀、切換速度快,內(nèi)存、資源占用小。線程缺點(diǎn):編程、調(diào)試復(fù)雜,可靠性較差。

上面的對(duì)比可以歸結(jié)為一句話:“線程快而進(jìn)程可靠性高”。線程有個(gè)別名叫“輕量級(jí)進(jìn)程”,在有的書(shū)籍資料上介紹線程可以十倍、百倍的效率快于進(jìn)程;而進(jìn)程之間不共享數(shù)據(jù),沒(méi)有鎖問(wèn)題,結(jié)構(gòu)簡(jiǎn)單,一個(gè)進(jìn)程崩潰不像線程那樣影響全局,因此比較可靠。我相信這個(gè)觀點(diǎn)可以被大部分人所接受,因?yàn)楹臀覀兯邮艿闹R(shí)概念是相符的。

在寫(xiě)這篇文章前,我也屬于這“大部分人”,這兩年在用C語(yǔ)言編寫(xiě)的幾個(gè)C/S通訊程序中,因時(shí)間緊總是采用多進(jìn)程并發(fā)技術(shù),而且是比較簡(jiǎn)單的現(xiàn)場(chǎng)為 每客戶fork()一個(gè)進(jìn)程,當(dāng)時(shí)總是擔(dān)心并發(fā)量增大時(shí)負(fù)荷能否承受,盤(pán)算著等時(shí)間充裕了將它改為多線程形式,或者改為預(yù)先創(chuàng)建進(jìn)程的形式,直到最近在網(wǎng)上看到了一篇論文《Linux系統(tǒng)下多線程與多進(jìn)程性能分析》才認(rèn)真思考這個(gè)問(wèn)題,我自己也做了實(shí)驗(yàn)。

下面是得出結(jié)論的實(shí)驗(yàn)步驟和過(guò)程,結(jié)論究竟是怎樣的?感興趣就一起看看吧。

實(shí)驗(yàn)代碼使用論文中的代碼樣例,做了少量修改,值得注意的是這樣的區(qū)別:

論文實(shí)驗(yàn)和我的實(shí)驗(yàn)時(shí)間不同,論文所處的年代linux內(nèi)核是2.4,我的實(shí)驗(yàn)linux內(nèi)核是2.6,2.6使用的線程庫(kù)是NPTL,2.4使用的是老的Linux線程庫(kù)(用進(jìn)程模擬線程的那個(gè)LinuxThread)。論文實(shí)驗(yàn)和我用的機(jī)器不同,論文描述了使用的環(huán)境:?jiǎn)蝐pu 機(jī)器基本配置為:celeron 2.0 GZ, 256M, Linux 9.2,內(nèi)核 2.4.8。我的環(huán)境是:雙核 Intel(R) Xeon(R) CPU 5130 @ 2.00GHz(做實(shí)驗(yàn)時(shí),禁掉了一核),512MG內(nèi)存,Red Hat Enterprise Linux ES release 4 (Nahant Update 4),內(nèi)核2.6.9-42。

進(jìn)程實(shí)驗(yàn)代碼(fork.c):

#include
#include
#include

#define P_NUMBER 255 //并發(fā)進(jìn)程數(shù)量
#define COUNT 5 //每次進(jìn)程打印字符串?dāng)?shù)
#define TEST_LOGFILE "logFile.log"
FILE *logFile=NULL;

char *s="hello linux?";

int main()
{
int i=0,j=0;
logFile=fopen(TEST_LOGFILE,"a+");//打開(kāi)日志文件
for(i=0;i {
if(fork()==0)//創(chuàng)建子進(jìn)程,if(fork()==0){}這段代碼是子進(jìn)程運(yùn)行區(qū)間
{
for(j=0;j {
printf("[%d]%sn",j,s);//向控制臺(tái)輸出
/*當(dāng)你頻繁讀寫(xiě)文件的時(shí)候,Linux內(nèi)核為了提高讀寫(xiě)性能與速度,會(huì)將文件在內(nèi)存中進(jìn)行緩存,這部分內(nèi)存就是Cache Memory(緩存內(nèi)存)??赡軐?dǎo)致測(cè)試結(jié)果不準(zhǔn),所以在此注釋*/
//fprintf(logFile,"[%d]%sn",j,s);//向日志文件輸出,
}
exit(0);//子進(jìn)程結(jié)束
}
}

for(i=0;i {
wait(0);
}

printf("Okayn");
return 0;
};i++)>;j++)
;i++)

線程實(shí)驗(yàn)代碼(thread.c):

#include
#include
#include
#include

#define P_NUMBER 255//并發(fā)線程數(shù)量
#define COUNT 5 //每線程打印字符串?dāng)?shù)
#define TEST_LOG "logFile.log"
FILE *logFile=NULL;

char *s="hello linux?";

print_hello_linux()//線程執(zhí)行的函數(shù)
{
int i=0;
for(i=0;i {
printf("[%d]%sn",i,s);//想控制臺(tái)輸出
/*當(dāng)你頻繁讀寫(xiě)文件的時(shí)候,Linux內(nèi)核為了提高讀寫(xiě)性能與速度,會(huì)將文件在內(nèi)存中進(jìn)行緩存,這部分內(nèi)存就是Cache Memory(緩存內(nèi)存)。可能導(dǎo)致測(cè)試結(jié)果不準(zhǔn),所以在此注釋*/
//fprintf(logFile,"[%d]%sn",i,s);//向日志文件輸出
}
pthread_exit(0);//線程結(jié)束
}

int main()
{
int i=0;
pthread_t pid[P_NUMBER];//線程數(shù)組
logFile=fopen(TEST_LOG,"a+");//打開(kāi)日志文件

for(i=0;i pthread_create(&pid[i],NULL,(void *)print_hello_linux,NULL);//創(chuàng)建線程

for(i=0;i pthread_join(pid[i],NULL);//回收線程

printf("Okayn");
return 0;
};i++)
;i++)
;i++)

兩段程序做的事情是一樣的,都是創(chuàng)建“若干”個(gè)進(jìn)程/線程,每個(gè)創(chuàng)建出的進(jìn)程/線程打印“若干”條“hello linux”字符串到控制臺(tái)和日志文件,兩個(gè)“若干”由兩個(gè)宏 P_NUMBER和COUNT分別定義,程序編譯指令如下:

gcc -o fork fork.c
gcc -lpthread -o thread thread.c

實(shí)驗(yàn)通過(guò)time指令執(zhí)行兩個(gè)程序,抄錄time輸出的掛鐘時(shí)間(real時(shí)間):

time ./fork
time ./thread

每批次的實(shí)驗(yàn)通過(guò)改動(dòng)宏 P_NUMBER和COUNT來(lái)調(diào)整進(jìn)程/線程數(shù)量和打印次數(shù),每批次測(cè)試五輪,得到的結(jié)果如下:

一、重復(fù)論文實(shí)驗(yàn)步驟

(注:本文平均值算法采用的是去掉一個(gè)最大值去掉一個(gè)最小值,然后平均)

圖片

圖片

圖片

圖片

圖片

圖片

圖片

圖片

本輪實(shí)驗(yàn)是為了和論文作對(duì)比,因此將進(jìn)程/線程數(shù)量限制在255個(gè),論文也是測(cè)試了255個(gè)進(jìn)程/線程分別進(jìn)行5次,10 次,50 次,100 次,500 次……10000 次打印的用時(shí),論文得出的結(jié)果是:任務(wù)量較大時(shí),多進(jìn)程比多線程效率高;而完成的任務(wù)量較小時(shí),多線程比多進(jìn)程要快,重復(fù)打印 600 次時(shí),多進(jìn)程與多線程所耗費(fèi)的時(shí)間相同。

雖然我的實(shí)驗(yàn)直到1000打印次數(shù)時(shí),多進(jìn)程才開(kāi)始領(lǐng)先,但考慮到使用的是NPTL線程庫(kù)的緣故,從而可以證實(shí)了論文的觀點(diǎn)。從我的實(shí)驗(yàn)數(shù)據(jù)看,多線程和多進(jìn)程兩組數(shù)據(jù)非常接近,考慮到數(shù)據(jù)的提取具有瞬間性,因此可以認(rèn)為他們的速度是相同的。

是不是可以得出這樣的結(jié)論:多線程創(chuàng)建、銷(xiāo)毀速度快,而多線程切換速度快,這個(gè)結(jié)論我們會(huì)在第二個(gè)試驗(yàn)中繼續(xù)試圖驗(yàn)證

當(dāng)前的網(wǎng)絡(luò)環(huán)境中,我們更看中高并發(fā)、高負(fù)荷下的性能,縱觀前面的實(shí)驗(yàn)步驟,最長(zhǎng)的實(shí)驗(yàn)周期不過(guò)2分鐘多一點(diǎn),因此下面的實(shí)驗(yàn)將向兩個(gè)方向延伸,第一,增加并發(fā)數(shù)量,第二,增加每進(jìn)程/線程的工作強(qiáng)度。

二、增加并發(fā)數(shù)量的實(shí)驗(yàn)

下面的實(shí)驗(yàn)打印次數(shù)不變,而進(jìn)程/線程數(shù)量逐漸增加。在實(shí)驗(yàn)過(guò)程中多線程程序在后四組(線程數(shù)350,500,800,1000)的測(cè)試中都出現(xiàn)了“段錯(cuò)誤”,出現(xiàn)錯(cuò)誤的原因和多線程預(yù)分配線程棧有關(guān)。

實(shí)驗(yàn)中的計(jì)算機(jī)CPU是32位,尋址最大范圍是4GB(2的32次方),Linux是按照3GB/1GB的方式來(lái)分配內(nèi)存,其中1GB屬于所有進(jìn)程共享的內(nèi)核空間,3GB屬于用戶空間(進(jìn)程虛擬內(nèi)存空間)。Linux2.6的默認(rèn)線程棧大小是8M(通過(guò)ulimit -a查看),對(duì)于多線程,在創(chuàng)建線程的時(shí)候系統(tǒng)會(huì)為每一個(gè)線程預(yù)分配線程棧地址空間,也就是8M的虛擬內(nèi)存空間。線程數(shù)量太多時(shí),線程棧累計(jì)的大小將超過(guò)進(jìn)程虛擬內(nèi)存空間大?。ㄓ?jì)算時(shí)需要排除程序文本、數(shù)據(jù)、共享庫(kù)等占用的空間),這就是實(shí)驗(yàn)中出現(xiàn)的“段錯(cuò)誤”的原因。

Linux2.6的默認(rèn)線程棧大小可以通過(guò) ulimit -s 命令查看或修改,我們可以計(jì)算出線程數(shù)的最大上線: (1024102410243) / (10241024*8) = 384,實(shí)際數(shù)字應(yīng)該略小與384,因?yàn)檫€要計(jì)算程序文本、數(shù)據(jù)、共享庫(kù)等占用的空間。在當(dāng)今的稍顯繁忙的WEB服務(wù)器上,突破384的并發(fā)訪問(wèn)并不是稀 罕的事情,要繼續(xù)下面的實(shí)驗(yàn)需要將默認(rèn)線程棧的大小減小,但這樣做有一定的風(fēng)險(xiǎn),比如線程中的函數(shù)分配了大量的自動(dòng)變量或者函數(shù)涉及很深的棧幀(典型的是 遞歸調(diào)用),線程棧就可能不夠用了??梢耘浜鲜褂肞OSIX.1規(guī)定的兩個(gè)線程屬性guardsize和stackaddr來(lái)解決線程棧溢出問(wèn) 題,guardsize控制著線程棧末尾之后的一篇內(nèi)存區(qū)域,一旦線程棧在使用中溢出并到達(dá)了這片內(nèi)存,程序可以捕獲系統(tǒng)內(nèi)核發(fā)出的告警信號(hào),然后使用 malloc獲取另外的內(nèi)存,并通過(guò)stackaddr改變線程棧的位置,以獲得額外的??臻g,這個(gè)動(dòng)態(tài)擴(kuò)展??臻g辦法需要手工編程,而且非常麻煩。

有兩種方法可以改變線程棧的大小,使用 ulimit -s 命令改變系統(tǒng)默認(rèn)線程棧的大小,或者在代碼中創(chuàng)建線程時(shí)通過(guò)pthread_attr_setstacksize函數(shù)改變棧尺寸,在實(shí)驗(yàn)中使用的是第一種,在程序運(yùn)行前先執(zhí)行ulimit指令將默認(rèn)線程棧大小改為1M:

ulimit -s 1024
time ./thread

圖片

圖片

圖片

圖片

圖片

圖片

【實(shí)驗(yàn)結(jié)論】

當(dāng)線程/進(jìn)程逐漸增多時(shí),執(zhí)行相同任務(wù)時(shí),線程所花費(fèi)時(shí)間相對(duì)于進(jìn)程有下降的趨勢(shì)(本人懷疑后兩組數(shù)據(jù)受系統(tǒng)其他瓶頸的影響),這是不是進(jìn)一步驗(yàn)證了多線程創(chuàng)建、銷(xiāo)毀速度快,而多進(jìn)程切換速度快。

三、增加每進(jìn)程/線程的工作強(qiáng)度的實(shí)驗(yàn)

這次將程序打印數(shù)據(jù)增大,原來(lái)打印字符串為:

char *s = "hello linux?";

現(xiàn)在修改為每次打印256個(gè)字節(jié)數(shù)據(jù):

char *s = "1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef
1234567890abcdef?";

圖片

圖片

圖片

【實(shí)驗(yàn)結(jié)論】

從上面的實(shí)驗(yàn)比對(duì)結(jié)果看,即使Linux2.6使用了NPTL線程庫(kù),多線程比較多進(jìn)程在效率上沒(méi)有任何的優(yōu)勢(shì),在線程數(shù)增大時(shí)多線程程序還出現(xiàn)了運(yùn)行錯(cuò)誤,實(shí)驗(yàn)可以得出下面的結(jié)論:

在Linux2.6上,多線程并不比多進(jìn)程速度快,考慮到線程棧的問(wèn)題,多進(jìn)程在并發(fā)上有優(yōu)勢(shì)。

四、多進(jìn)程和多線程在創(chuàng)建和銷(xiāo)毀上的效率比較

預(yù)先創(chuàng)建進(jìn)程或線程可以節(jié)省進(jìn)程或線程的創(chuàng)建、銷(xiāo)毀時(shí)間,在實(shí)際的應(yīng)用中很多程序使用了這樣的策略,比如Apapche預(yù)先創(chuàng)建進(jìn)程、Tomcat 預(yù)先創(chuàng)建線程,通常叫做進(jìn)程池或線程池。在大部分人的概念中,進(jìn)程或線程的創(chuàng)建、銷(xiāo)毀是比較耗時(shí)的,在stevesn的著作《Unix網(wǎng)絡(luò)編程》中有這樣 的對(duì)比圖(第一卷 第三版 30章 客戶/服務(wù)器程序設(shè)計(jì)范式):

圖片

stevens已駕鶴西去多年,但《Unix網(wǎng)絡(luò)編程》一書(shū)仍具有巨大的影響力,上表中stevens比較了三種服務(wù)器上多進(jìn)程和多線程的執(zhí)行效 率,因?yàn)槿N服務(wù)器所用計(jì)算機(jī)不同,表中數(shù)據(jù)只能縱向比較,而橫向無(wú)可比性,stevens在書(shū)中提供了這些測(cè)試程序的源碼(也可以在網(wǎng)上下載)。書(shū)中介 紹了測(cè)試環(huán)境,兩臺(tái)與服務(wù)器處于同一子網(wǎng)的客戶機(jī),每個(gè)客戶并發(fā)5個(gè)進(jìn)程(服務(wù)器同一時(shí)間最多10個(gè)連接),每個(gè)客戶請(qǐng)求從服務(wù)器獲取4000字節(jié)數(shù)據(jù), 預(yù)先派生子進(jìn)程或線程的數(shù)量是15個(gè)。

第0行是迭代模式的基準(zhǔn)測(cè)試程序,服務(wù)器程序只有一個(gè)進(jìn)程在運(yùn)行(同一時(shí)間只能處理一個(gè)客戶請(qǐng)求),因?yàn)闆](méi)有進(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)場(chǎng)fork子進(jìn)程,2~5行都是預(yù)先創(chuàng)建15個(gè)子進(jìn)程模式,在多進(jìn)程程序中套接字傳遞不太容易(相對(duì)于多線 程),stevens在這里提供了4個(gè)不同的處理accept的方法。6~8行是多線程服務(wù)模式,第6行是現(xiàn)場(chǎng)為客戶請(qǐng)求創(chuàng)建子線程,7~8行是預(yù)先創(chuàng)建 15個(gè)線程。表中有的格子是空白的,是因?yàn)檫@個(gè)系統(tǒng)不支持此種模式,比如當(dāng)年的BSD不支持線程,因此BSD上多線程的數(shù)據(jù)都是空白的。

從數(shù)據(jù)的比對(duì)看,現(xiàn)場(chǎng)為每客戶fork一個(gè)進(jìn)程的方式是最慢的,差不多有20倍的速度差異,Solaris上的現(xiàn)場(chǎng)fork和預(yù)先創(chuàng)建子進(jìn)程的最大差別是504.2 :21.5,但我們不能理解為預(yù)先創(chuàng)建模式比現(xiàn)場(chǎng)fork快20倍,原因有兩個(gè):

  1. stevens的測(cè)試已是十幾年前的了,現(xiàn)在的OS和CPU已起了翻天覆地的變化,表中的數(shù)值需要重新測(cè)試。
  2. stevens沒(méi)有提供服務(wù)器程序整體的運(yùn)行計(jì)時(shí),我們無(wú)法理解504.2 :21.5的實(shí)際運(yùn)行效率,有可能是1504.2 : 1021.5,也可能是100503.2 : 100021.5,20倍的差異可能很大,也可能可以忽略。

因此我寫(xiě)了下面的實(shí)驗(yàn)程序,來(lái)計(jì)算在Linux2.6上創(chuàng)建、銷(xiāo)毀10萬(wàn)個(gè)進(jìn)程/線程的絕對(duì)用時(shí)。

創(chuàng)建10萬(wàn)個(gè)進(jìn)程(forkcreat.c):

#include
#include
#include
#include
#include
#include
#include
#include

int count;//子進(jìn)程創(chuàng)建成功數(shù)量
int fcount;//子進(jìn)程創(chuàng)建失敗數(shù)量
int scount;//子進(jìn)程回收數(shù)量

/*信號(hào)處理函數(shù)–子進(jìn)程關(guān)閉收集*/
void sig_chld(int signo)
{
pid_t chldpid;//子進(jìn)程id
int stat;//子進(jìn)程的終止?fàn)顟B(tài)

//子進(jìn)程回收,避免出現(xiàn)僵尸進(jìn)程
while((chldpid=wait(&stat)>0))
{
scount++;
}
}

int main()
{
//注冊(cè)子進(jìn)程回收信號(hào)處理函數(shù)
signal(SIGCHLD,sig_chld);

int i;
for(i=0;i<100000;i++)//fork()10萬(wàn)個(gè)子進(jìn)程
{
pid_t pid=fork();
if(pid==-1)//子進(jìn)程創(chuàng)建失敗
{
fcount++;
}
else if(pid>0)//子進(jìn)程創(chuàng)建成功
{
count++;
}
else if(pid==0)//子進(jìn)程執(zhí)行過(guò)程
{
exit(0);
}
}

printf("count:%d fount:%d scount:%dn",count,fcount,scount);
}

創(chuàng)建10萬(wàn)個(gè)線程(pthreadcreat.c):

#include
#include

int count=0;//成功創(chuàng)建線程數(shù)量

void thread(void)
{
//啥也不做
}

int main(void)
{
pthread_t id;//線程id
int i,ret;

for(i=0;i<100000;i++)//創(chuàng)建10萬(wàn)個(gè)線程
{
ret=pthread_create(&id,NULL,(void *)thread,NULL);
if(ret!=0)
{
printf("Create pthread error!n");
return(1);
}
count++;
pthread_join(id,NULL);
}

printf("count:%dn",count);
}

圖片

從數(shù)據(jù)可以看出,多線程比多進(jìn)程在效率上有10多倍的優(yōu)勢(shì),但不能讓我們?cè)谑褂媚姆N并發(fā)模式上定性,這讓我想起多年前政治課上的一個(gè)場(chǎng)景:在講到優(yōu)越性時(shí),面對(duì)著幾個(gè)對(duì)此發(fā)表質(zhì)疑評(píng)論的調(diào)皮男生,我們的政治老師發(fā)表了高見(jiàn),“不能只橫向地和當(dāng)今的發(fā)達(dá)國(guó)家比,你應(yīng)該縱向地和過(guò)去中國(guó)幾十年的發(fā)展歷史 比”。政治老師的話套用在當(dāng)前簡(jiǎn)直就是真理,我們看看,即使是在賽揚(yáng)CPU上,創(chuàng)建、銷(xiāo)毀進(jìn)程/線程的速度都是空前的,可以說(shuō)是有質(zhì)的飛躍的,平均創(chuàng)建銷(xiāo)毀一個(gè)進(jìn)程的速度是0.18毫秒,對(duì)于當(dāng)前服務(wù)器幾百、幾千的并發(fā)量,還有預(yù)先派生子進(jìn)程/線程的必要嗎?

預(yù)先派生子進(jìn)程/線程比現(xiàn)場(chǎng)創(chuàng)建子進(jìn)程/線程要復(fù)雜很多,不僅要對(duì)池中進(jìn)程/線程數(shù)量進(jìn)行動(dòng)態(tài)管理,還要解決多進(jìn)程/多線程對(duì)accept的“搶” 問(wèn)題,在stevens的測(cè)試程序中,使用了“驚群”和“鎖”技術(shù)。即使stevens的數(shù)據(jù)表格中,預(yù)先派生線程也不見(jiàn)得比現(xiàn)場(chǎng)創(chuàng)建線程快,在 《Unix網(wǎng)絡(luò)編程》第三版中,新作者參照stevens的測(cè)試也提供了一組數(shù)據(jù),在這組數(shù)據(jù)中,現(xiàn)場(chǎng)創(chuàng)建線程模式比預(yù)先派生線程模式已有了效率上的優(yōu)勢(shì)。因此我對(duì)這一節(jié)實(shí)驗(yàn)下的結(jié)論是:

預(yù)先派生進(jìn)程/線程的模式(進(jìn)程池、線程池)技術(shù),不僅復(fù)雜,在效率上也無(wú)優(yōu)勢(shì),在新的應(yīng)用中可以放心大膽地為客戶連接請(qǐng)求去現(xiàn)場(chǎng)創(chuàng)建進(jìn)程和線程。

我想,這是fork迷們最愿意看到的結(jié)論了。

五、雙核系統(tǒng)重復(fù)論文實(shí)驗(yàn)步驟

圖片

圖片

圖片

圖片

【實(shí)驗(yàn)結(jié)論】

雙核處理器在完成任務(wù)量較少時(shí),沒(méi)有系統(tǒng)其他瓶頸因素影響時(shí)基本上是單核的兩倍,在任務(wù)量較多時(shí),受系統(tǒng)其他瓶頸因素的影響,速度明顯趨近于單核的速度。

六、并發(fā)服務(wù)的不可測(cè)性

看到這里,你會(huì)感覺(jué)到我有挺進(jìn)程、貶線程的論調(diào),實(shí)際上對(duì)于現(xiàn)實(shí)中的并發(fā)服務(wù)具有不可測(cè)性,前面的實(shí)驗(yàn)和結(jié)論只可做參考,而不可定性。

結(jié)束語(yǔ)

本篇文章比較了Linux系統(tǒng)上多線程和多進(jìn)程的運(yùn)行效率,在實(shí)際應(yīng)用時(shí)還有其他因素的影響,比如網(wǎng)絡(luò)通訊時(shí)采用長(zhǎng)連接還是短連接,是否采用 select、poll,這些都可能影響到并發(fā)模式的選型。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    10908

    瀏覽量

    213109
  • Linux系統(tǒng)
    +關(guān)注

    關(guān)注

    4

    文章

    596

    瀏覽量

    27522
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7614

    瀏覽量

    137800
  • Web服務(wù)器
    +關(guān)注

    關(guān)注

    0

    文章

    138

    瀏覽量

    24491
  • 多線程
    +關(guān)注

    關(guān)注

    0

    文章

    278

    瀏覽量

    20076
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    進(jìn)程線程區(qū)別

    )。不管是多進(jìn)程還是多線程,最終目標(biāo)都是實(shí)現(xiàn)并行執(zhí)行。 2、多線程的優(yōu)勢(shì)前些年多進(jìn)程多一些,近些年多線程開(kāi)始用得多?,F(xiàn)代操作
    發(fā)表于 11-30 14:06

    多線程多進(jìn)程的區(qū)別

    6.你的數(shù)據(jù)庫(kù)一會(huì)又500個(gè)連接數(shù),一會(huì)有10個(gè),你分析一下情況7.udp和tcp的區(qū)別8.多線程多進(jìn)程的區(qū)別9.有一臺(tái)web服務(wù)器,你選擇用多線程還是多進(jìn)程,...
    發(fā)表于 07-19 07:21

    淺談多進(jìn)程多線程的選擇

    問(wèn)題,那就沒(méi)有這么簡(jiǎn)單了,選的不好,會(huì)讓你深受其害。 經(jīng)常在網(wǎng)絡(luò)看到有的XDJM問(wèn)“多進(jìn)程好還是多線程好?”、“Linux下用多進(jìn)程還是
    發(fā)表于 08-24 07:38

    python多線程多進(jìn)程對(duì)比

    。就好像,電視播完正劇,進(jìn)入廣告時(shí)間,我們卻不能去趁廣告時(shí)間是吃個(gè)飯。對(duì)于程序來(lái)說(shuō),這樣做顯然是效率極低的,是不合理的。雖然 多線程 和 協(xié)程 已經(jīng)相當(dāng)智能了。但還是不夠高效,最高效的應(yīng)該是一心多用,邊看
    發(fā)表于 03-15 16:42

    LINUX系統(tǒng)多線程多進(jìn)程性能分析

    采用多進(jìn)程處理多個(gè)任務(wù),會(huì)占用很多系統(tǒng)資源(主要是CPU 和內(nèi)存的使用)。在LINUX 中,則對(duì)這種弊端進(jìn)行了改進(jìn),在用戶態(tài)實(shí)現(xiàn)了多線程處理多任務(wù)。本文
    發(fā)表于 08-13 08:31 ?20次下載

    linux多線程編程技術(shù)

    (process)中只允許有一個(gè)線程,這樣多線程就意味著多進(jìn)程?,F(xiàn)在,多線程技術(shù)已經(jīng)被許多操作系統(tǒng)所支持,包括Windows/NT,當(dāng)然,也
    發(fā)表于 10-24 16:01 ?5次下載

    如何選好多線程多進(jìn)程

    關(guān)于多進(jìn)程多線程,教科書(shū)上最經(jīng)典的一句話是“進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位”,這句話應(yīng)付考試基本夠了,但如果在工作
    的頭像 發(fā)表于 05-11 16:16 ?3022次閱讀
    如何選好<b class='flag-5'>多線程</b>和<b class='flag-5'>多進(jìn)程</b>

    多進(jìn)程多線程的深度比較

    嵌入式Linux中文站,關(guān)于多進(jìn)程多線程,教科書(shū)上最經(jīng)典的一句話是“進(jìn)程是資源分配的最小單位,線程是CPU調(diào)度的最小單位”
    發(fā)表于 04-02 14:42 ?508次閱讀

    Linux下的多線程編程

    進(jìn)程(process)中只允許有一個(gè)線程,這樣多線程就意味著多進(jìn)程?,F(xiàn)在,多線程技術(shù)已經(jīng)被許多操作系統(tǒng)
    發(fā)表于 04-02 14:43 ?641次閱讀

    多進(jìn)程多線程的基本概念

    顯然高于并發(fā)運(yùn)行,所以在多CPU的計(jì)算機(jī)中,多任務(wù)的效率比較高。但是,如果在多CPU計(jì)算機(jī)中只運(yùn)行一個(gè)進(jìn)程(線程),就不能發(fā)揮多CPU的優(yōu)勢(shì)
    發(fā)表于 04-02 14:49 ?768次閱讀

    Python多進(jìn)程學(xué)習(xí)

    Python 多進(jìn)程 (Multiprocessing) 是一種同時(shí)利用計(jì)算機(jī)多個(gè)處理器核心 (CPU cores) 進(jìn)行并行處理的技術(shù),它與 Python 的多線程 (Multithreading
    的頭像 發(fā)表于 04-26 11:04 ?605次閱讀

    淺談Linux網(wǎng)絡(luò)編程中的多進(jìn)程多線程

    Linux網(wǎng)絡(luò)編程中,我們應(yīng)該見(jiàn)過(guò)很多網(wǎng)絡(luò)框架或者server,有多進(jìn)程的處理方式,也有多線程處理方式,孰好孰壞并沒(méi)有可比性,首先選擇多進(jìn)程還是
    發(fā)表于 08-08 16:56 ?864次閱讀
    淺談<b class='flag-5'>Linux</b>網(wǎng)絡(luò)編程中的<b class='flag-5'>多進(jìn)程</b>和<b class='flag-5'>多線程</b>

    關(guān)于Python多進(jìn)程多線程詳解

    進(jìn)程(process)和線程(thread)是操作系統(tǒng)的基本概念,但是它們比較抽象,不容易掌握。關(guān)于多進(jìn)程多線程,教科書(shū)上最經(jīng)典的一句話是
    的頭像 發(fā)表于 11-06 14:46 ?914次閱讀
    關(guān)于Python<b class='flag-5'>多進(jìn)程</b>和<b class='flag-5'>多線程</b>詳解

    你還是分不清多進(jìn)程多線程嗎?一文搞懂!

    你還是分不清多進(jìn)程多線程嗎?一文搞懂! 多進(jìn)程多線程是并發(fā)編程中常見(jiàn)的兩個(gè)概念,它們都可以用于提高程序的性能和效率。但是它們的實(shí)現(xiàn)方式和
    的頭像 發(fā)表于 12-19 16:07 ?627次閱讀

    Python中多線程多進(jìn)程的區(qū)別

    Python作為一種高級(jí)編程語(yǔ)言,提供了多種并發(fā)編程的方式,其中多線程多進(jìn)程是最常見(jiàn)的兩種方式之一。在本文中,我們將探討Python中多線程多進(jìn)程的概念、區(qū)別以及如何使用
    的頭像 發(fā)表于 10-23 11:48 ?500次閱讀
    Python中<b class='flag-5'>多線程</b>和<b class='flag-5'>多進(jìn)程</b>的區(qū)別