Python和其他進程的管道通信方式--popen和popen2的比較


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

     char * name = args[1] 
     printf("%s",getid(name) ); 

 
 
  
  python程序調用的片段如下:
 
    pipe = os.popen( "get_user_id " + "myname"
 
    user_id    = pipe.read() 
     
      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改后
  
 
int main( int argc ,  char* args[]) 
       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次查詢
 
   
import os 
 
if __name__ ==  "__main__"
     
    pipe_in , pipe_out = popen2( "get_user_id""wr"); 
     for i  in range(10000) 
        pipe_in.write("myname"); 
        pipe_in.write("\n"); #需要換行符
        pipe_in.flush(); #需要清空緩沖區
         
        userid = pipe_out.readline(); #讀入結果
 
 
 上述情況需要注意的是,為了和進程順利交互,一般需要flush,防止io緩沖;盡量寫入和讀入整行,方便控制管道交互過程。
 
 根據筆者試驗顯示:使用常駐內存的進程進行10000次調用,比不常駐內存的進程快得多,前者耗費的時間大約是后者的1/5,不過這個結果只是筆者的特例。請讀者分析自己的應用場合,看看如何使用python強大的管道工具。
 
 ps,python還有popen3,可打開進程的stdin,stdout和stderr,更好更強大。另外subprocess 模塊下有更強大的進程管理接口。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM