Python 关闭前冲洗管道(操作系统管道)

Python 关闭前冲洗管道(操作系统管道),python,pipe,ipc,buffering,Python,Pipe,Ipc,Buffering,我需要启动一个子进程并启用两个线程分别读取其stdout和stderr 以下代码正在考虑标准输出: def reader(rfd): while True: try: data = os.read(rfd, bufsize) except OSError: break else: chomp(data) rout, wout = os.pipe() tout = th

我需要启动一个子进程并启用两个线程分别读取其
stdout
stderr

以下代码正在考虑标准输出:

def reader(rfd):
    while True:
        try:
            data = os.read(rfd, bufsize)
        except OSError:
            break
        else:
            chomp(data)

rout, wout = os.pipe()
tout = threading.Thread(target=reader, args=(rout,))
tout.start()

subprocess.check_call(command, bufsize=bufsize, stdout=wout, stderr=werr)

os.close(wout)
os.close(rout)
tout.join()
代码可以工作,只是我注意到并不是所有的数据都被处理过,就好像
os.close(wout)
函数在读取所有数据之前杀死了读卡器一样。另一方面,如果我不关闭
wout
,我的进程将永远挂在
tout.join()

我可以看出这是一个缓冲问题,因为如果我在
子进程之后放置一个非常糟糕的
时间。sleep(0.1)
。检查调用(…)
一切都会神奇地工作

好的方法是刷新而不是等待,但是通过管道调用
os.fsync()
会给出
OSError:[Errno 22]无效参数


关于如何刷新使用
os.pipe
创建的管道的任何提示?

在确定进程已完成写入之前,您无法关闭管道(因为您将丢失数据),并且您不能等待线程完成而不关闭管道(因为
os.read
将永远阻塞)

您需要等待流程完成,并手动关闭管道的写入端(因为您创建了它)

下面是一个独立的示例:

import os
import threading
import subprocess

def reader(rfd):
    while True:
        try:
            data = os.read(rfd, bufsize)
            if not data:
                break #reached EOF
        except OSError:
            break

bufsize=100

rout, wout = os.pipe()
rerr, werr = os.pipe()

tout = threading.Thread(target=reader, args=(rout,))
tout.start()

p= subprocess.Popen("ls", bufsize=bufsize, stdout=wout, stderr=werr)
p.wait() #wait for the proces to end writing
os.close(wout)
os.close(werr)
tout.join()
os.close(rout)
os.close(rerr)

我建议使用
Popen
而不是
os.pipe
进行进程间通信

例如

但是,如果您真的想使用
os.pipe
,那么您将可以更轻松地将它们视为文件对象。Python内置的文件上下文管理器将确保适当地刷新和关闭文件

例如


为什么在连接螺纹之前要关闭管道?@goncalopp,
关闭
会中断
读取
。如果执行相反的操作,则会出现死锁,因为线程从未终止。您是否尝试过使用
subprocess.Popen
stdout=subprocess.PIPE
?另外,你确定问题不在于调用关闭
rout
吗?@Dunes,我没有这么做,因为我知道全部内容(在我的情况下,这将是巨大的)。但现在我意识到,即使不使用管道,也可以指定管道。我试试看。如果这行得通,我会让你知道的。关于关闭
rout
,如果我不关闭,线程在读取时会卡住。@Dacav是的,当然-但它会处理所有数据,对吗?您只需等待进程完成,然后关闭写入结束。我会在稍后的回答中提到这一点
writer_process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
reader_thread = threading.Thread(target=reader, args=(writer_process.stdout,))
reader_thread.start()
reader_thread.join()
def reader(fd):
    with os.fdopen(fd, bufsize=bufsize) as f:
        while True:
            data = f.read(bufsize)
            if not data:
                break
            chomp(data)
with os.fdopen(wout, "w", bufsize=bufsize) as f:
    subprocess.check_call(cmd, stdout=f)