你基本上有两个重叠的控制线程。
- 将输入发送到子流程。
- 在子进程可用时从子进程中读取数据。
除了使用线程(或者可能是选择循环)之外,以独立于平台的方式执行此操作不会给您太多选择。
您有问题的代码似乎只对标准输出感兴趣,因此您可以调用一个读取标准输出并将内容写入文件的线程。
这是一个例子:
import subprocess
import os
import threading
class LogThread(threading.Thread):
"""Thread which will read from `pipefd` and write all contents to
`fileobj` until `pipefd` is closed. Used as a context manager, this thread
will be automatically started, and joined on exit, usually when the
child process exits.
"""
def __init__(self, pipefd, fileobj):
self.pipefd = pipefd
self.fileobj = fileobj
super(LogThread, self).__init__()
self.setDaemon(1)
self.start()
def run(self):
while True:
line = self.pipefd.readline()
if not line:
break
self.fileobj.write(line)
self.fileobj.flush()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.join()
# Here's how to use the LogThread.
p = subprocess.Popen ("script", shell = False, stdin = subprocess.PIPE, stdout = subprocess.PIPE)
with open('logfile.txt', 'wt') as logfile:
with LogThread(p.stdout, logfile):
p.stdin.write("\n".join(in_lines))
p.stdin.close()
这可能会复制一小部分Popen.communicate()
但它不是很多代码并且与平台无关。
关于缓冲的注意事项:
stdout 缓冲到非 tty 设备(例如管道)是正常的。通常,stderr 没有缓冲。您通常无法控制正在运行的应用程序是否缓冲其输出。充其量您可以猜测它如何确定是否使用缓冲,大多数应用程序调用isatty()
以确定它是否应该缓冲。因此,在日志文件上设置缓冲 0 可能不是避免缓冲的正确解决方案。如果缓冲为 0,则输出的每个字符都作为单个write()
调用写入,效率非常低。上述解决方案已被修改为执行行缓冲。
以下链接可能有用:https ://unix.stackexchange.com/questions/25372/turn-off-buffering-in-pipe