簡體   English   中英

在Python中派生多個Shell命令/進程的最佳方法?

[英]Best way to fork multiple shell commands/processes in Python?

我在os.forkos.fork / multiprocessing模塊上看到的大多數示例都展示了如何派生調用Python腳本或Python代碼塊的新實例。 並發生成一組任意shell命令的最佳方法是什么?

我想,我可以只使用subprocess.callPopen命令之一並將輸出通過管道傳輸到文件,我相信該文件將立即返回,至少返回給調用者。 我知道這並不難做到,我只是想找出最簡單,最Python的方式來做到這一點。

提前致謝

subprocess.Popen所有調用都會立即返回給調用者。 waitcommunicate哪個塊的電話。 因此,您需要做的就是使用subprocess.Popen (為安全起見將stdin設置為/ dev / null)啟動多個進程,然后一個個地調用進行communicate直到它們全部完成為止。

自然地,我假設您只是嘗試啟動一堆不相關的命令(即未通過管道傳輸)。

我想,我可以只給我們subprocess.call或Popen命令之一,然后將輸出通過管道傳遞到文件,我相信它將立即返回,至少返回給調用者。

如果要處理數據,那不是一個好方法。

在這種情況下,最好做

sp = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)

然后使用sp.communicate()或直接從sp.stdout.read()讀取。

如果以后要在調用程序中處理數據,則有兩種處理方法:

  1. 您可以通過一個單獨的線程盡快檢索數據,讀取數據並將其存儲在消費者可以獲取的位置。

  2. 您可以讓生產子流程具有block並在需要時從中檢索數據。 子進程將產生盡可能多的數據,以適合管道緩沖區(通常為64 kiB),然后在進一步寫入時阻塞。 一旦需要數據,就從子進程對象的stdout (也可能是stderr read()並使用它們-或者,稍后再使用sp.communicate()

如果生成數據需要很多時間,那么方法1將會走,所以您的wprogram必須等待。

如果數據的大小非常大和/或數據生成的速度太快以至於緩沖將毫無意義,則將首選方法2。

我喜歡使用PTY而不是管道。 對於一堆只希望捕獲錯誤消息的過程,我這樣做了。

RNULL = open('/dev/null', 'r')
WNULL = open('/dev/null', 'w')
logfile = open("myprocess.log", "a", 1)
REALSTDERR = sys.stderr
sys.stderr = logfile

下一部分是一個循環,產生約30個進程。

sys.stderr = REALSTDERR
master, slave = pty.openpty()
self.subp = Popen(self.parsed, shell=False, stdin=RNULL, stdout=WNULL, stderr=slave)
sys.stderr = logfile

之后,我有了一個select循環,該循環收集了所有錯誤消息並將其發送到單個日志文件。 使用PTY意味着我不必擔心部分線會混淆,因為線規提供了簡單的框架。

在所有可能的情況下都沒有最好的方法。 最好取決於手頭的問題。

這是生成程序並將其輸出保存到結合stdout / stderr的文件中的方法:

import subprocess
import sys

def spawn(cmd, output_file):
    on_posix = 'posix' in sys.builtin_module_names
    return subprocess.Popen(cmd, close_fds=on_posix, bufsize=-1,
                            stdin=open(os.devnull,'rb'),
                            stdout=output_file,
                            stderr=subprocess.STDOUT)

要生成可以與腳本以及彼此並行運行的多個進程,請執行以下操作:

processes, files = [], []
try:
    for i, cmd in enumerate(commands):
        files.append(open('out%d' % i, 'wb'))
        processes.append(spawn(cmd, files[-1]))
finally:
    for p in processes:
        p.wait()
    for f in files: 
        f.close()

注意: cmd到處都是列表。

查看我的舊答案,包括要執行的代碼段

  • 使用進程而不是線程來阻塞I / O,因為可以更可靠地p.terminated()
  • 實現可重觸發的超時監視程序,該監視程序在發生某些輸出時重新開始計數
  • 實現長期超時看門狗以限制整體運行時間
  • 可以輸入標准輸入(盡管我只需要輸入一次短字符串)
  • 可以使用通常的Popen手段捕獲stdout / stderr(僅對stdout進行編碼,並且將stderr重定向到stdout;但可以輕松將其分離)
  • 這幾乎是實時的,因為它僅每0.2秒檢查一次輸出。 但是您可以減少此時間或輕松刪除等待間隔
  • 仍然啟用了許多調試打印輸出,以查看何時發生了什么。

要生成多個並發命令,您將需要更改類RunCmd來實例化多個讀取輸出/寫入輸入隊列並生成多個Popen子進程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM