|
我們?cè)诔绦蛑邢M麍?zhí)行shell命令的時(shí)候首先想到的system函數(shù),這個(gè)函數(shù)很簡(jiǎn)單,但有一個(gè)嚴(yán)重的問(wèn)題,就是他的執(zhí)行方式,效率上可能不高。
system函數(shù)首先建立一個(gè)新的進(jìn)程,然后在新的進(jìn)程中執(zhí)行exec函數(shù)去執(zhí)行我們的shell命令,然后阻塞等待shell命令執(zhí)行完后,返回到調(diào)用
函數(shù),system之所以要建立新的進(jìn)程,是因?yàn)?,exec函數(shù)的調(diào)用會(huì)結(jié)束調(diào)用進(jìn)程,從調(diào)用exec函數(shù)開(kāi)始,進(jìn)程就切換到執(zhí)行shell命令的進(jìn)程,
無(wú)法回到調(diào)用exec的進(jìn)程繼續(xù)執(zhí)行程序的余下部分。所以system就會(huì)新建進(jìn)程去執(zhí)行exec,exec結(jié)束掉system創(chuàng)建進(jìn)程,返回的時(shí)候,將
返回值送給調(diào)用system的進(jìn)程。換句話說(shuō),system建立的進(jìn)程就是為了給exec函數(shù)結(jié)束用的。 但我也查了相關(guān)資料,linux對(duì)system函數(shù)做了很好的優(yōu)化,在system建立進(jìn)程的時(shí)候,不會(huì)像建立普通進(jìn)程那樣消耗系統(tǒng)的資源,system進(jìn)程只有用到數(shù)據(jù)的時(shí)候,系統(tǒng)才為其分配,如果只是單純的執(zhí)行shell命令,效率還是很高。 但我總覺(jué)得,每次執(zhí)行個(gè)shell命令都調(diào)用system很不舒服,尤其是在線程中建立一個(gè)新的進(jìn)程更是感覺(jué)很怪。linux中存在另一種執(zhí)行shell命令的方法,就是管道,我就想測(cè)試一下,popen與system的效率誰(shuí)更高。 小程序如下:使用system與popen都執(zhí)行1000次ls -l 命令,并將輸出指向 /dev/NULL(即不在控制臺(tái)顯示輸出結(jié)果)。 view plaincopy to clipboardprint? #include<iostream> #include<stdio.h> #include <stdlib.h> #include<deque> #include<sys/time.h> using namespace std; timeval start,end; double timeuse; void time() { gettimeofday( &end, NULL ); timeuse = (1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec -\ start.tv_usec)/1000000; printf("time used: %f s\n", timeuse); } int main(int argc, char** argv) {
gettimeofday(&start,NULL); for(int i=0;i<1000;i++) { //system("ls -l >/dev/null 2>&1 "); popen( "ls -l >/dev/null 2>&1 ", "r" ); } time(); return 0; } #include<iostream> #include<stdio.h> #include <stdlib.h> #include<deque> #include<sys/time.h> using namespace std; timeval start,end; double timeuse; void time() { gettimeofday( &end, NULL ); timeuse = (1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec -\ start.tv_usec)/1000000; printf("time used: %f s\n", timeuse); } int main(int argc, char** argv) { gettimeofday(&start,NULL); for(int i=0;i<1000;i++) { //system("ls -l >/dev/null 2>&1 "); popen( "ls -l >/dev/null 2>&1 ", "r" ); } time(); return 0; } system函數(shù)執(zhí)行結(jié)果: 
popen函數(shù)執(zhí)行結(jié)果: 
如圖所示,當(dāng)使用system函數(shù)的時(shí)候?qū)pu的占用很大,但對(duì)內(nèi)存的消耗很少,執(zhí)行時(shí)間是14秒左右,當(dāng)使用popen的時(shí)候,對(duì)cpu的消耗很小,
但內(nèi)存的使用直線上升,執(zhí)行時(shí)間是9秒左右,速度明顯提升。我的測(cè)試很可能片面不準(zhǔn)確,希望有時(shí)間再進(jìn)行其他方面的比較。 備注:popen與system popen 內(nèi)存上升原因是因?yàn)槲覜](méi)有執(zhí)行close函數(shù),如果執(zhí)行的話,內(nèi)存上升應(yīng)該不大,綜上,還是使用popen效率跟高。
popen() 可以在調(diào)用程序和POSIX shell /usr/bin/sh 要執(zhí)行的命令之間創(chuàng)建一個(gè)管道(請(qǐng)參閱sh-posix(1) )。 popen() 的參數(shù)是指向以空字符結(jié)尾的字符串的指針,這些字符串分別包含一個(gè)shell 命令行和一個(gè)I/O 模式,此 模式可以是進(jìn)行讀取的r ,或進(jìn)行寫(xiě)入的w 。 popen() 可返回一個(gè)流指針,這樣,當(dāng)I/O 模式為w 時(shí),便可以通過(guò)寫(xiě)入文件stream 來(lái)寫(xiě)入到命令的標(biāo)準(zhǔn)輸入; 當(dāng)I/O 模式為r 時(shí),通過(guò)從文件stream 讀取數(shù)據(jù),從命令的標(biāo)準(zhǔn)輸出讀取數(shù)據(jù)。 popen() 打開(kāi)的流應(yīng)由pclose() 關(guān)閉,這需要等待終止關(guān)聯(lián)的進(jìn)程,然后返回命令的退出狀態(tài)。 因?yàn)榇蜷_(kāi)的文件是共享的,所以類(lèi)型為r 的命令可用作輸入過(guò)濾器,類(lèi)型為w 的命令可用作輸出過(guò)濾器。
system() 可執(zhí)行由command 指向的字符串指定的命令。已執(zhí)行命令的環(huán)境就如同使用fork() (請(qǐng)參閱fork(2) ) 創(chuàng)建了一個(gè)子進(jìn)程,子進(jìn)程按以下方式通過(guò)調(diào)用execl() (請(qǐng)參閱exec(2) )來(lái)調(diào)用sh-posix(1) 實(shí)用程序: execl("/usr/bin/sh", "sh", "-c", command, 0); system() 在等待命令終止時(shí)將忽略SIGINT 和SIGQUIT 信號(hào),同時(shí)阻塞SIGCHLD 信號(hào)。如果這會(huì)導(dǎo)致應(yīng)用程 序錯(cuò)過(guò)一個(gè)終止它的信號(hào),則應(yīng)用程序應(yīng)檢查system() 的返回值;如果由于收到某個(gè)信號(hào)而終止了命令,應(yīng)用程 序應(yīng)采取一切適當(dāng)?shù)拇胧? system() 不影響除自己創(chuàng)建的一個(gè)或多個(gè)進(jìn)程以外的調(diào)用進(jìn)程的任何子進(jìn)程的終止?fàn)顟B(tài)。 在子進(jìn)程終止之前, system() 不會(huì)返回。
|