这里没有答案能满足我的所有需求。
- 没有用于stdout的线程(也没有队列等)
- 非阻塞,因为我需要检查其他情况
- 根据需要使用PIPE来执行多项操作,例如流输出,写入日志文件并返回输出的字符串副本。
一些背景知识:我正在使用ThreadPoolExecutor来管理线程池,每个线程都启动一个子进程并运行它们的并发性。(在Python2.7中,但这也应在较新的3.x中运行)。我不想仅将线程用于输出收集,因为我希望尽可能多的线程可用于其他事情(20个进程的池将仅使用40个线程来运行; 1个用于进程线程,而1个用于stdout ...还有更多,如果您想要stderr,我猜)
我在这里剥离了很多异常,因此这是基于可在生产环境中使用的代码的。希望我不会在复制粘贴时毁了它。另外,非常欢迎反馈!
import time
import fcntl
import subprocess
import time
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Make stdout non-blocking when using read/readline
proc_stdout = proc.stdout
fl = fcntl.fcntl(proc_stdout, fcntl.F_GETFL)
fcntl.fcntl(proc_stdout, fcntl.F_SETFL, fl | os.O_NONBLOCK)
def handle_stdout(proc_stream, my_buffer, echo_streams=True, log_file=None):
"""A little inline function to handle the stdout business. """
# fcntl makes readline non-blocking so it raises an IOError when empty
try:
for s in iter(proc_stream.readline, ''): # replace '' with b'' for Python 3
my_buffer.append(s)
if echo_streams:
sys.stdout.write(s)
if log_file:
log_file.write(s)
except IOError:
pass
# The main loop while subprocess is running
stdout_parts = []
while proc.poll() is None:
handle_stdout(proc_stdout, stdout_parts)
# ...Check for other things here...
# For example, check a multiprocessor.Value('b') to proc.kill()
time.sleep(0.01)
# Not sure if this is needed, but run it again just to be sure we got it all?
handle_stdout(proc_stdout, stdout_parts)
stdout_str = "".join(stdout_parts) # Just to demo
我确定这里要增加开销,但是这对我来说不是问题。从功能上来说,它可以满足我的需求。我唯一没有解决的问题就是为什么这对于日志消息非常有效,但是我看到一些print
消息稍后出现,并且一次全部出现。