先进先出 - 循环读取

13

我想使用os.mkfifo来实现程序之间的简单通讯。但是在使用循环读取FIFO时遇到了问题。

考虑这个玩具例子,其中有一个读者和一个写者通过FIFO进行通讯。我希望能够在一个循环中运行读者以读取进入FIFO的所有内容。

# reader.py
import os
import atexit

FIFO = 'json.fifo'

@atexit.register
def cleanup():
    try:
        os.unlink(FIFO)
    except:
        pass

def main():
    os.mkfifo(FIFO)
    with open(FIFO) as fifo:
#        for line in fifo:              # closes after single reading
#        for line in fifo.readlines():  # closes after single reading
        while True:
            line = fifo.read()          # will return empty lines (non-blocking)
            print repr(line)

main()

而这位作家:

# writer.py
import sys

FIFO = 'json.fifo'


def main():
    with open(FIFO, 'a') as fifo:
        fifo.write(sys.argv[1])

main()
如果我运行python reader.py,然后稍后运行python writer.py foo,将打印出"foo",但是fifo将关闭并且读取程序将退出(或在while循环中旋转)。 我希望阅读器保持在循环中,因此可以多次执行写入程序。 编辑 我使用以下代码片段来处理此问题:
def read_fifo(filename):
    while True:
        with open(filename) as fifo:
            yield fifo.read()

也许有更简便的方式来处理它,而不是重复打开文件...

相关

3个回答

7

您无需反复重新打开文件。您可以使用

with open(FIFO_PATH) as fifo:
    while True:
        select.select([fifo],[],[fifo])
        data = fifo.read()
        do_work(data)

在这个例子中,您将不会读取EOF。

我认为这是更好的答案,因为它不会使用 while 循环消耗 CPU 周期。 - huggie
1
如果 writer 关闭,它似乎会一直循环,这种情况下可以参考链接:https://dev59.com/FVkT5IYBdhLWcg3wFrsT,或者使用 for line in fifo 代替 fifo.read() - huggie

5

在读取端,FIFO 的工作方式如下:可以一直读取,直到所有的写入者都离开。然后向读取者发送 EOF 信号。

如果你想让读取者继续读取,就必须重新打开并从那里读取。所以你的片段是正确的方法。

如果有多个写入者,则必须确保它们写入的每个数据部分都小于 PIPE_BUF,以避免混淆消息。


我想,对于多个写入者,我应该使用更高级的东西,因为这里的写入者会关闭彼此的FIFO,而且一个写入者的数据可能会与另一个写入者的数据混合。 - Jakub M.
它们不会相互关闭,如果写入的数据足够小,它们也不会相互干扰。有一个常量PIPE_BUF告诉您数据包可以变得多大而不会相互干扰。 - glglgl

0

在标准库的 pathlib.Path 类中,以下方法对此非常有帮助:

这里有一个演示:

# reader.py
import os
from pathlib import Path

fifo_path = Path("fifo")
os.mkfifo(fifo_path)

while True:
    print(fifo_path.read_text())  # blocks until data becomes available

# writer.py
import sys
from pathlib import Path

fifo_path = Path("fifo")
assert fifo_path.is_fifo()

fifo_path.write_text(sys.argv[1])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接