2012-05-02 51 views
5

我遇到了一些困难,从子流程标准输出管道获取输出。我正在通过它启动一些第三方代码,以提取日志输出。直到最近更新的第三方代码,一切正常。更新之后,python已经无限期地开始阻塞,并且没有实际显示任何输出。我可以手动启动第三方应用程序并查看输出。窗口上的Python子流程输出?

我正在使用的代码的基本版本:

import subprocess, time 
from threading import Thread 

def enqueue_output(out): 
    print "Hello from enqueue_output" 
    for line in iter(out.readline,''): 
     line = line.rstrip("\r\n") 
     print "Got %s" % line 
    out.close() 

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=1) 
thread = Thread(target=enqueue_output, args=(proc.stdout,)) 
thread.daemon = True 
thread.start() 

time.sleep(30) 

这工作完全,如果我代替third_party.exe这个脚本:

import time, sys 

while True: 
    print "Test" 
    sys.stdout.flush() 
    time.sleep(1) 

所以我不清楚魔需要完成这项工作才能使用原始命令。

这些都是我没有成功尝试subprocess.Popen线的所有变体:

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=0) 
proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, shell=True) 
proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, creationflags=subprocess.CREATE_NEW_CONSOLE) 
si = subprocess.STARTUPINFO() 
si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW 
proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, startupinfo=si) 

编辑1: 我实际上并不能在这种情况下使用.communicate()。我启动的应用程序仍在运行很长一段时间(几天到几周)。我实际上可以测试.communicate()的唯一方法就是在启动后不久就杀死该应用程序,我不觉得会给我有效的结果。

即使这个非线程版本失败:

import subprocess, time 
from threading import Thread 

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

print "App started, reading output..." 
for line in iter(proc.stdout.readline,''): 
    line = line.rstrip("\r\n") 
    print "Got: %s" % line 

编辑2: 由于JDI,以下的作品没关系:

import tempfile, time, subprocess 

w = "test.txt" 
f = open("test.txt","a") 
p = subprocess.Popen("third_party.exe", shell=True, stdout=f, 
         stderr=subprocess.STDOUT, bufsize=0) 

time.sleep(30) 

with open("test.txt", 'r') as r: 
    for line in r: 
     print line 
f.close() 
+0

是否有可能您的第三方程序切换到写入stderr? – jdi

+0

似乎并非如此。如果我拦截stderr,则会发生同样的情况(尽管如此,我确实在控制台上看到了应用程序的输出,但它只是打印,不会通过Python)。 – devicenull

+0

听起来好像应用程序已停止使用标准输出并直接写入控制台。如果是这样,你可以做的不多。你能检查应用程序的供应商吗? –

回答

5

首先,我会建议您简化此示例确保你可以真正阅读任何东西。从混合中删除线程的复杂性:

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=1) 
print proc.communicate() 

如果这样的话,很好。然后,您可能会直接或者可能在线程中读取标准输出。

如果这不起作用,你有没有尝试将stderr管道输出到stdout呢?

proc = subprocess.Popen("third_party.exe", 
         stdout=subprocess.PIPE, 
         stderr=subprocess.STDOUT, bufsize=1) 

更新

既然你说communicate()被死锁,这里是另一种方法,你可以尝试看看,如果它与子进程的内部缓冲区问题...

import tempfile 
import subprocess 

w = tempfile.NamedTemporaryFile() 
p = subprocess.Popen('third_party.exe', shell=True, stdout=w, 
         stderr=subprocess.STDOUT, bufsize=0) 

with open(w.name, 'r') as r: 
    for line in r: 
     print line 
w.close() 
+0

如果我在线程出现错误,为什么它可以用于我的简单测试应用程序,但不是真实的东西?我无法使用沟通,因为应用程序实际上并没有结束。它是一台服务器,并且长时间保持运行。 – devicenull

+0

@devicenull:我会说不同之处在于,您的测试脚本每秒都会慢慢地打印4个字符,而我不知道您的第三方应用程序正在执行何种输出。你可能会从缓冲区中死锁。而且,当你有这样的问题时,它总是尽可能地去除尽可能多的变量,并确保每一步都能正常工作。 – jdi

+0

输出到一个文件完美。任何想法,为什么工作,但管道不? – devicenull

2
args = ['svn','log','-v'] 

def foo(info=''): 
    import logging 
    import subprocess 
    import tempfile 
    try: 
     pipe = subprocess.Popen(args,bufsize = 0,\ 
      stdout = subprocess.PIPE,\ 
      stderr=subprocess.STDOUT) 
    except Exception as e: 
     logging.error(str(e)) 
     return False 
    while 1: 
     s = pipe.stdout.read() 
     if s: 
      print s, 
     if pipe.returncode is None: 
      pipe.poll() 
     else: 
      break 
    if not 0 == pipe.returncode: 
     return False 
    return True 

print foo() 

这一个应该工作,而不是线程,临时文件魔术。

相关问题