我有一个关于 python 中的命名管道或类似内容的问题,以及它们是否可以适用于我的用例。我有类似以下代码的内容。
fn = path/to/my/file.ext
os.mkfifo(fn)
subprocess.check_output(args=(bar -o fn).split())
foo(fn)
我的目标是不将子进程栏的输出写入光盘,而是将其直接通过管道传输到
foo()
函数中。遗憾的是, foo()
函数只接受文件名,而不接受任何类型的描述符/句柄。因此,我需要定义某种内存文件,子进程和 foo()
函数都可以使用它。据我了解,命名管道非常接近我在这里想要的,但是它被设计为仅在两端连接时工作,而不是作为内存文件/缓冲区中的某些中间体,因此它已经在子进程调用处挂起(有可能但我正在做/理解错误的事情)。命名管道是正确的方法还是我应该使用其他方法?
(此外,我也想避免像
os.O_NONBLOCK
这样的事情,因为它们只适用于 Linux)
foo()
函数仅从文件中读取。
非常感谢您的帮助!
命名管道是解决此问题的有效方法。您当前的方法失败,因为
subprocess.check_output
等待进程终止。除非您排空管道,否则不会发生这种情况。因此,第一个修复方法是调用 subprocess.Popen
并让进程在您从管道中读取数据时继续运行。
但是,这又带来了一个新问题:
fn
如何知道该过程已完成?通常,您会一直读取到文件结尾 (EOF)。当写入端关闭时,管道会发出 EOF 信号。对于命名管道,文件系统中的文件条目是一个写入器(打开管道的子进程算作第二个写入器)。因此 fn
将无限期地等待 EOF。
您需要做的是在该过程完成后删除命名管道。最简单的方法是使用单独的线程。
import os
from os import path
import subprocess
import tempfile
import threading
def call_bar(fifo_name):
try:
subprocess.check_output(args=("bar", "-o", fifo_name))
finally:
os.remove(fifo_name)
# Python doesn't have a function for safe creation of temporary named
# fifos. So we resort to a temporary directory
with tempfile.TemporaryDirectory() as tmpdir:
fifo_name = path.join(tmpdir.name, "fifo")
os.mkfifo(fifo_name)
with threading.Thread(target=call_bar, args=(fifo_name,)):
foo(fifo_name)
这样做有一个问题:如果进程在
fn
打开管道之前终止,则第二个线程可能会在 fn
有机会打开管道之前删除该管道。我想如果子进程没有创建输出,就会发生这种情况。该异常应该很容易捕获。