目前有一個查詢程序 get_user_id 是用C寫的,python需要調用這個程序:使用 get_user_id "用戶名" 可以得到輸出: "ID0002451".
在python中使用管道可以方便的調用這個進程並得到它的標准輸出:
get_user_id 是C寫的,程序大概的框架如下:得到一個命令行參數,然后根據參數打印其相應的id:








python程序調用的片段如下:



pipe.close()
python是這樣調用get_user_id程序的。 首先python會啟動一個子進程,然后讀入子進程的標准輸出,最后結束子進程。 這里的主要的開銷是進程的啟動和撤銷,管道之間的通信是非常快的。
如果get_user_id調用得不太頻繁,則這種調用方式沒有問題;若get_user_id調用得很頻繁,以致它的性能成為了系統的瓶頸,這就有必要優化了。優化的方法是使得get_user_id子進程常駐內存,python父進程可以使用write/flush和readline的方法和子進程通信;程序結束時撤銷子進程。
進程常駐內存后,python只需要啟動一次子進程就可以滿足任意次的查詢。不過帶來的麻煩是get_user_id程序需要重寫:將它改為在循環中接收標准輸入,把結果送往標准輸出,另外約定一個特殊的輸入(如"EOF"),子進程收到這個輸入后退出循環。
get_user_id改后



char name[512]; // buff
while( scanf("%s", name) ){

if (!strcmp(name,"EOF")) return 0;
printf("%s\n",getid(name) );

}
}



這個C程序先接受標准輸入,判斷輸入是否結束為結束標志,如果是則返回,否則打印用戶ID。
Python應該如何調用這個進程呢?使用popen()得到的pipe對象只支持write或者read操作,而不能同時讀和寫。
需要同時允許讀寫操作,使用popen2()。該函數返回一個包涵兩個元素的tuple,這兩個元素依次是寫管道(即可向目標進程寫入標准輸入)和讀管道(即讀進程的標准輸出)。
如果需要和上述C程序打交道,則應該這樣打開管道
pipe_out , pipe_in = popen2( " get_user_id " , "wr");
"wr"表示次管道需要先寫后讀。
具體例子如下:進行10000次查詢












上述情況需要注意的是,為了和進程順利交互,一般需要flush,防止io緩沖;盡量寫入和讀入整行,方便控制管道交互過程。
根據筆者試驗顯示:使用常駐內存的進程進行10000次調用,比不常駐內存的進程快得多,前者耗費的時間大約是后者的1/5,不過這個結果只是筆者的特例。請讀者分析自己的應用場合,看看如何使用python強大的管道工具。
ps,python還有popen3,可打開進程的stdin,stdout和stderr,更好更強大。另外subprocess 模塊下有更強大的進程管理接口。