subprocess是python在2.4引入的模塊, 主要用來替代下面幾個模塊和方法:html
os.system
os.spawn*
os.popen*
popen2.*
commands.*python
能夠參考PEP324: http://legacy.python.org/dev/peps/pep-0324/sql
這是一個用來調用外部命令的模塊, 替代了一些舊的模塊, 提供了更加友好統一的接口.shell
三個封裝方法windows
使用下面三個方法的時候, 注意兩個問題: 1. shell=True或False, 兩種解析方式是不一樣的 2. 注意PIPE的使用, 可能致使卡死緩存
subprocess.call 運行命令, 等待完成, 並返回returncode安全
subprocess.check_call 運行命令, 等待完成, 若是返回值爲0, 則返回returncode, 不然拋出帶有returncode的CalledPorcessError異常.oop
subprocess.check_output 和check_call相似, 會檢查返回值是否爲0, 返回stdout.性能
卡死常見的緣由spa
這個模塊在使用的時候, 可能會出現子進程卡死或hang住的狀況. 通常出現這種狀況的是這樣的用法.
import subprocess import shlex proc = subprocess.Popen(shlex.split(cmd), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False, universal_newlines=True) print proc.stdout.read()
這裏的直接讀取了Popen對象的stdout, 使用了subprocess.PIPE. 這種狀況致使卡死的緣由是PIPE管道的緩存被充滿了, 沒法繼續寫入, 也沒有將緩存中的東西讀出來.
官方文檔的提示(Popen.wait()方法的Warning)
This will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.
爲了解決這個問題, Popen有一個communicate方法, 這個方法會將stdout和stderr數據讀入到內存, 而且會一直獨到兩個流的結尾(EOF). communicate能夠傳入一個input參數, 用來表示向stdin中寫入數據, 能夠作到進程間的數據通訊.
注意: 官方文檔中提示, 讀取的數據是緩存在內存中的, 因此當數據量很是大或者是無限制的時候, 不要使用communicate, 應該會致使OOM.
通常狀況下, stdout和stderr數據量不是很大的時候, 使用communicate不會致使問題, 量特別大的時候能夠考慮使用文件來替代PIPE, 例如stdout=open("stdout", "w")[參考1].
參考2中給出了另外一種解決的思路, 使用select來讀取Popen的stdout和stderr中的數據, select的這種用法windows下是不支持的, 不過能夠作到比較實時的讀取數據.
Popen中的shell參數含義
官方文檔中推薦shell=False, 這種方式更加安全, 咱們來看一下官方給出的例子.
>>> from subprocess import call >>> filename = input("What file would you like to display?\n") What file would you like to display? non_existent; rm -rf / # >>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...
上面這種命令拼寫的方式會致使一個安全問題, 就是用戶能夠進行相似sql注入的shell注入, 刪除整個系統的文件, 這個是極其危險的.
shell=False會屏蔽shell中的不少特性, 因此能夠避免上述這種安全問題, 當須要暴露給用戶去使用的時候, 尤爲要注意上述的安全問題.
shell=True的時候就是按照shell的方式解析和運行的.
Popen的一些簡單調優思路
有個bufsize的參數, 這個默認是0, 就是不緩存, 1表示行緩存, 其餘正數表示緩存使用的大小, 負數-1表示是使用系統默認的緩存大小.
在運行性能遇到問題時, 多是緩存區未開啓或者過小, 致使了子進程被卡住, 效率低下, 能夠考慮配置爲-1或4096.
須要實時讀取stdout和stderr的, 能夠查閱[參考2], 使用select來讀取stdout和stderr流.
參考: