我在从子进程stdout管道获取输出时遇到了一些困难。我正在通过它启动一些第三方代码,以便提取日志输出。直到最近更新第三方代码,一切正常。更新后,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 :(得分:5)
首先,我建议您简化此示例,以确保您可以实际阅读任何内容。从混合中删除线程的复杂性:
proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=1)
print proc.communicate()
如果有效,那很好。然后你可能会遇到直接或可能在你的线程中阅读stdout的问题。
如果这不起作用,你是否尝试过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()
答案 1 :(得分: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()
这个应该有效,而不是线程,临时文件魔术。