2009-05-17 38 views
44

我想使用的子模塊以下列方式:如何獲得「實時」信息反饋從subprocess.Popen在Python(2.5)

  1. 潛在創建新進程需要很長時間才能執行。
  2. 捕獲stdout(或stderr,或可能兩者一起或單獨)從子
  3. 過程數據,因爲它涉及在,在每一行或者觸發事件接收(在wxPython中說),或僅僅打印出來目前。

我已經用Popen創建了進程,但是如果我使用通信(),那麼一旦進程終止,數據就會一次全部到達我。

如果我創建了一個單獨的線程來執行阻止readline()的​​(使用stdout = subprocess.PIPE),我也沒有收到此方法的任何行,直到進程終止。 (不管我設置爲bufsize)

有沒有辦法處理這個不可怕,並且在多個平臺上運行良好?

+2

myprocess.stdout.readline()應該工作。你能告訴我們你的代碼嗎? – 2009-05-17 15:28:35

+0

來自popen_obj.stdout()的未緩衝讀取確實可行 - 但如果您不介意僅限於支持PTY的平臺,則您的應用程序可能適用於Pexpect庫。 – 2009-05-17 15:46:38

+1

這是一個很好的問題,至少對於「在多個平臺上很好地工作」的要求,似乎仍然沒有答案。 – 2011-03-22 00:01:03

回答

7

標準輸出將被緩衝 - 所以你不會得到任何東西,直到該緩衝區被填滿,或子進程退出。

您可以嘗試從子進程或使用stderr刷新stdout,或在非緩存模式下更改stdout。

2

聽起來像這個問題可能是由子進程使用緩衝輸出 - 如果創建的輸出相對較少,則可以緩存直到子進程退出。有些背景,可以發現here

與代碼
8

更新出現不工作(在Windows反正)

class ThreadWorker(threading.Thread): 
    def __init__(self, callable, *args, **kwargs): 
     super(ThreadWorker, self).__init__() 
     self.callable = callable 
     self.args = args 
     self.kwargs = kwargs 
     self.setDaemon(True) 

    def run(self): 
     try: 
      self.callable(*self.args, **self.kwargs) 
     except wx.PyDeadObjectError: 
      pass 
     except Exception, e: 
      print e 



if __name__ == "__main__": 
    import os 
    from subprocess import Popen, PIPE 

    def worker(pipe): 
     while True: 
      line = pipe.readline() 
      if line == '': break 
      else: print line 

    proc = Popen("python subprocess_test.py", shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE) 

    stdout_worker = ThreadWorker(worker, proc.stdout) 
    stderr_worker = ThreadWorker(worker, proc.stderr) 
    stdout_worker.start() 
    stderr_worker.start() 
    while True: pass 
2

這裏對我來說什麼工作:

cmd = ["./tester_script.bash"] 
p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
while p.poll() is None: 
    out = p.stdout.readline() 
    do_something_with(out, err) 

在你的情況,你可以嘗試到子過程的引用傳遞給你的工作線程,並執行線程內投票。我不知道當兩個線程輪詢(並與之交互)同一個子進程時它的行爲如何,但它可能工作。

另請注意,泰特while p.poll() is None:的意圖是。做而不是用python 0替換爲while not p.poll()(成功終止的返回碼)也被認爲是False

1

我也遇到過這個問題。出現問題的原因是您也嘗試讀取stderr。如果沒有錯誤,則嘗試從stderr讀取將會阻止。

在Windows上,沒有簡單的方法來輪詢()文件描述符(只有Winsock套接字)。

所以一個解決方案是不要試圖從stderr讀取。

1

使用非阻塞readlines的pexpect [http://www.noah.org/wiki/Pexpect]將解決此問題。它源於管道被緩衝的事實,因此你的應用的輸出被管道緩衝,因此在緩衝區填充或進程死亡之前你不能到達那個輸出。

1

這似乎是一個衆所周知的Python限制,請參閱 PEP 3145和其他人。同時

1

讀取一個字符:http://blog.thelinuxkid.com/2013/06/get-python-subprocess-output-without.html

import contextlib 
import subprocess 

# Unix, Windows and old Macintosh end-of-line 
newlines = ['\n', '\r\n', '\r'] 
def unbuffered(proc, stream='stdout'): 
    stream = getattr(proc, stream) 
    with contextlib.closing(stream): 
     while True: 
      out = [] 
      last = stream.read(1) 
      # Don't loop forever 
      if last == '' and proc.poll() is not None: 
       break 
      while last not in newlines: 
       # Don't loop forever 
       if last == '' and proc.poll() is not None: 
        break 
       out.append(last) 
       last = stream.read(1) 
      out = ''.join(out) 
      yield out 

def example(): 
    cmd = ['ls', '-l', '/'] 
    proc = subprocess.Popen(
     cmd, 
     stdout=subprocess.PIPE, 
     stderr=subprocess.STDOUT, 
     # Make all end-of-lines '\n' 
     universal_newlines=True, 
    ) 
    for line in unbuffered(proc): 
     print line 

example() 
0

使用subprocess.Popen,我可以運行我的C#項目之一的.exe和輸出重定向到我的Python文件。我現在可以將print()的所有信息輸出到C#控制檯(使用Console.WriteLine())到Python控制檯。

Python代碼:

from subprocess import Popen, PIPE, STDOUT 

p = Popen('ConsoleDataImporter.exe', stdout = PIPE, stderr = STDOUT, shell = True) 

while True: 
    line = p.stdout.readline() 
    print(line) 
    if not line: 
     break 

這得由我行.NET項目線的控制檯輸出,創建並打破了封閉的它,而在該項目的終止循環。我想這也適用於兩個python文件。