我在運行Python 2.6的Linux機器上並行運行多個命令,這可能需要一些時間。更好的多線程使用Python subprocess.Popen&communications()?
因此,我使用subprocess.Popen
類和process.communicate()
方法來並行執行多個命令組並在執行後立即捕獲輸出。
def run_commands(commands, print_lock):
# this part runs in parallel.
outputs = []
for command in commands:
proc = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
output, unused_err = proc.communicate() # buffers the output
retcode = proc.poll() # ensures subprocess termination
outputs.append(output)
with print_lock: # print them at once (synchronized)
for output in outputs:
for line in output.splitlines():
print(line)
在別的地方,它被稱爲是這樣的:
processes = []
print_lock = Lock()
for ...:
commands = ... # a group of commands is generated, which takes some time.
processes.append(Thread(target=run_commands, args=(commands, print_lock)))
processes[-1].start()
for p in processes: p.join()
print('done.')
預期的結果是一組命令的每個輸出在一次,而他們的執行並行完成顯示。
但是從第二個輸出組(當然,由於調度不確定性而變成第二個線程),它開始打印而沒有換行符,並且添加的空格數與前一行中打印的字符數和輸入回顯關閉 - 終端狀態爲「亂碼」或「崩潰」。 (如果我發出reset
shell命令,它恢復正常。)
起初,我試圖找到處理'\r'
的原因,但它不是原因。正如您在我的代碼中看到的那樣,我使用splitlines()
正確處理了它,並且我確認了使用repr()
函數應用於輸出。
我認爲原因是在Popen
和communicate()
管道stdout/stderr併發使用管道。我在Python 2.7中嘗試了check_output
快捷方法,但沒有成功。當然,如果我序列化所有命令的執行和打印,則不會發生上述問題。
有沒有更好的方法可以並行處理Popen
和communicate()
?
`.communicate()`確保進程完成,因爲它調用`Popen.wait()`。但`proc.poll()`不能確保進程完成。如果進程沒有完成,它將返回`None`。例如在Linux上,它調用`waitpid(pid,WNOHANG)`。 WNOHANG的文檔說:「如果狀態不是立即可用於由pid指定的某個子進程,則waitpid()函數不會暫停執行調用線程。」 http://www.mkssoftware.com/docs/man3/waitpid.3。asp – jfs 2010-11-26 19:57:08
以下是腳本,它並行運行所有進程,並按進程組輸出組,以保持組內的順序https://gist.github.com/717467 – jfs 2010-11-27 01:50:45
感謝Sebastian,但是您的解決方案並未完全解決問題。這似乎是Python的子流程實現及其同步中的一個錯誤。我添加了最終結果作爲答案。 – Achimnol 2010-11-28 20:15:43