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:控制 stdin, stdout, stderr 等引數指定的檔案的緩衝,和開啟檔案的 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)