Python 中的命名管道(缓冲区?)或共享内存文件

问题描述 投票:0回答:1

我有一个关于 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()
函数仅从文件中读取。

非常感谢您的帮助!

python python-3.x shared-memory named-pipes
1个回答
1
投票

命名管道是解决此问题的有效方法。您当前的方法失败,因为

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
有机会打开管道之前删除该管道。我想如果子进程没有创建输出,就会发生这种情况。该异常应该很容易捕获。

© www.soinside.com 2019 - 2024. All rights reserved.