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