2011-11-11 39 views
2

我在os.fork和subprocess/multiprocessing模塊中看到的大多數示例都展示瞭如何分派調用python腳本的新實例或一段python代碼。什麼是同時生成一組任意shell命令的最好方法?在Python中分叉多個shell命令/進程的最佳方式是什麼?

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

在此先感謝

回答

3

所有來電立即subprocess.Popen返回給調用者。這是撥打waitcommunicate的電話。所以你所需要做的就是使用subprocess.Popen(爲了安全起見將stdin設置爲/ dev/null),然後逐個調用communicate,直到它們全部完成。

當然,我假設你只是試圖開始一堆無關的(即不配管)命令。

+0

是的,我認爲這就是我需要的。我正在努力做到這一點。我想分解這個過程,讓他們做他們的事情,稍後再回來,在運行一些其他的命令後,grep他們的輸出。謝謝! – mrmbd

1

我想,我可能只是我們subprocess.call或POPEN 命令和管道的一個輸出到一個文件,我相信會立即返回 ,至少給調用者。

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

在這種情況下,更好地做好

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

然後sp.communicate()或直接從sp.stdout.read()讀取。

如果數據應在調用程序在稍後的時間進行處理,有兩種方法去:

  1. 您可以儘快獲取數據,通過一個單獨的線程也許,閱讀他們和存儲它們在消費者可以得到它們的地方。

  2. 您可以讓生產子進程在您需要時阻止並從中檢索數據。子進程產生儘可能多的數據以適應管道緩衝區(通常爲64kB),然後阻塞進一步的寫入。只要你需要這些數據,你就可以從子流程對象的stdout(也可能是stderr)中獲得read()並使用它們 - 或者,在以後再次使用sp.communicate()

如果生成數據需要很多時間,方法1將走,因此您的wprogram將不得不等待。

如果數據的大小相當巨大,並且/或者數據產生得太快以至於緩衝沒有意義,則方式2將是優選的。

+0

我應該補充說,我確實想要處理數據,但不是馬上處理它,也就是說它可能是一個長時間運行的進程,某種服務器,並且在我分叉之後,我的腳本將不再執行其他操作。當我回到分支進程時,我可能只是grep其輸出文件的錯誤。 。 。 – mrmbd

+0

編輯以顯示檢索和處理如何工作。 – glglgl

1

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

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意味着我從不必擔心部分線條混淆,因爲線條規則提供了簡單的構圖。

1

沒有最適合所有可能的情況。最好的取決於手頭的問題。

以下是如何產卵一個過程,它的輸出保存到一個文件合併標準輸出/標準錯誤:

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是無處不在的列表。

+0

「對所有可能的情況都沒有最好的。」 - 我認爲大部分時間都是這樣,我想我只是想要一些建議。 – mrmbd

+1

@mrmbd:我打算說這個問題對於這樣一個複雜的話題來說太廣泛了。 – jfs

0

參見an older answer of mine including code snippets做:

  • 使用進程不線程阻塞I/O,因爲它們可以更可靠地p.terminated()
  • 實現一個可再觸發的超時監視該重新啓動每當一些輸出發生計數
  • 實現長期超時看門狗限制整體運行
  • 可以在標準輸入飼料(雖然我只需要一次性喂短字符串)
  • 可以捕獲stdout/stderr中的通常Popen方式(只有stdout被編碼,並且stderr被重定向到stdout;但可以很容易地分開)
  • 這幾乎是實時的,因爲它只會每0.2秒檢查一次輸出。但是你可以減少這個或者輕鬆地刪除等待間隔
  • 許多調試打印輸出仍然可以看到什麼時候發生。

對於產生多個併發命令,您需要更改類RunCmd以實例化多讀讀取輸出/寫入輸入隊列併產生多重Popen子進程。

相關問題