1. 程式人生 > >Python多程序(1)——subprocess與Popen()

Python多程序(1)——subprocess與Popen()

  Python多程序方面涉及的模組主要包括:

  • multiprocessing:提供支援多處理器技術的多程序程式設計介面,並且介面的設計最大程度地保持了和threading模組的一致,便於理解和使用。

  本文主要介紹 subprocess 模組及其提供的 Popen 類,以及如何使用該構造器在一個程序中建立新的子程序。此外,還會簡要介紹 subprocess 模組提供的其他方法與屬性,這些功能上雖然沒有 Popen 強大的工具,在某些情況下卻非常方便和高效。

  本文的目錄如下:

  1. subprocess.Popen 類

  2. Popen 物件的屬性

  3. Popen 物件的方法

  4. subprocess模組的其他簡便方法

  5. subprocess模組的其他屬性

  6. subprocess模組定義的異常

subprocess.Popen 類

  通過呼叫:

subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

  建立並返回一個子程序,並在這個程序中執行指定的程式。

  例項化 Popen 可以通過許多引數詳細定製子程序的環境,但是隻有一個引數是必須的,即位置引數 args ,下面也會詳細介紹剩餘的具名引數。

引數介紹:

  • args:要執行的命令或可執行檔案的路徑。一個由字串組成的序列(通常是列表),列表的第一個元素是可執行程式的路徑,剩下的是傳給這個程式的引數,如果沒有要傳給這個程式的引數,args 引數可以僅僅是一個字串。
  • bufsize:控制 stdinstdoutstderr 等引數指定的檔案的緩衝,和開啟檔案的 open()函式中的引數 bufsize 含義相同。
  • executable:如果這個引數不是 None,將替代引數 args 作為可執行程式;
  • stdin:指定子程序的標準輸入;
  • stdout:指定子程序的標準輸出;
  • stderr:指定子程序的標準錯誤輸出;

  對於 stdin, stdout 和 stderr 而言,如果他們是 None(預設情況),那麼子程序使用和父程序相同的標準流檔案。

  父程序如果想要和子程序通過 communicate() 方法通訊,對應的引數必須是 subprocess.PIPE(見下文例4);

  當然 stdin, stdout 和 stderr 也可以是已經開啟的 file 物件,前提是以合理的方式開啟,比如 stdin 對應的檔案必須要可讀等。 

  • preexec_fn:預設是None,否則必須是一個函式或者可呼叫物件,在子程序中首先執行這個函式,然後再去執行為子程序指定的程式或Shell。
  • close_fds:布林型變數,為 True 時,在子程序執行前強制關閉所有除 stdin,stdout和stderr外的檔案;
  • shell:布林型變數,明確要求使用shell執行程式,與引數 executable 一同指定子程序執行在什麼 Shell 中——如果executable=None 而 shell=True,則使用 /bin/sh 來執行 args 指定的程式;也就是說,Python首先起一個shell,再用這個shell來解釋指定執行的命令。
  • cwd:代表路徑的字串,指定子程序執行的工作目錄,要求這個目錄必須存在;
  • env:字典,鍵和值都是為子程序定義環境變數的字串;
  • universal_newline:布林型變數,為 True 時,stdout 和 stderr 以通用換行(universal newline)模式開啟,
  • startupinfo:見下一個引數;
  • creationfalgs:最後這兩個引數是Windows中才有的引數,傳遞給Win32的CreateProcess API呼叫。

  同 Linux 中建立子程序類似,父程序建立完子程序後,並不會自動等待子程序執行,父程序在子程序之前推出將導致子程序成為孤兒程序,孤兒程序統一由 init 程序接管,負責其終止後的回收工作。

  如果父程序在子程序之後終止,但子程序終止時父程序沒有進行最後的回收工作,子程序殘留的資料結構稱為殭屍程序。大量殭屍程序將耗費系統資源,因此父程序及時等待和回收子程序是必要的,除非能夠確認自己比子程序先終止,從而將回收工作過渡給 init 程序。

  這個等待和回收子程序的操作就是wait()函式,下文中將會介紹。

例1:

  建立一個子程序,然後執行一個簡單的命令

1 2 3 4 5 6 7 8 9 10 11 >>> import subprocess >>> p = subprocess.Popen('ls -l', shell=True) >>> total 164 -rw-r--r--  1 root root   133 Jul  4 16:25 admin-openrc.sh -rw-r--r--  1 root root   268 Jul 10 15:55 admin-openrc-v3.sh ... >>> p.returncode >>> p.wait() 0 >>> p.returncode 0

  這裡也可以使用 p = subprocess.Popen(['ls', '-cl']) 來建立子程序。

Popen 物件的屬性

  Popen建立的子程序有一些有用的屬性,假設 p 是 Popen 建立的子程序,p 的屬性包括:

1. 

p.pid

  子程序的PID。

 2. 

p.returncode

  該屬性表示子程序的返回狀態,returncode可能有多重情況:

  • None —— 子程序尚未結束;
  • ==0 —— 子程序正常退出;
  • > 0—— 子程序異常退出,returncode對應於出錯碼;
  • < 0—— 子程序被訊號殺掉了。

 3. 

p.stdin, p.stdout, p.stderr

  子程序對應的一些初始檔案,如果呼叫Popen()的時候對應的引數是subprocess.PIPE,則這裡對應的屬性是一個包裹了這個管道的 file 物件,

Popen 物件的方法

1.

p.poll()

  檢查子程序  p 是否已經終止,返回 p.returncode 屬性 (參考下文 Popen 物件的屬性);

2.

p.wait()

  等待子程序 p 終止,返回 p.returncode 屬性;

  注意:

    wait() 立即阻塞父程序,直到子程序結束!

3.

p.communicate(input=None)