如何在Python中正确写入FIFO?

28 投票
2 回答
32321 浏览
提问于 2025-04-16 23:31

在Python中打开FIFO(命名管道)进行写入时,发生了一些非常奇怪的事情。想象一下,当我在交互式解释器中尝试打开一个FIFO进行写入时,会发生什么:

>>> fifo_write = open('fifo', 'w')

上面的代码会一直停在那里,直到我打开另一个解释器并输入以下内容:

>>> fifo_read = open('fifo', 'r')
>>> fifo.read()

我不明白为什么我必须等到管道被打开用于读取,但我们先不讨论这个。上面的代码会一直等待,直到有数据可用,这个是正常的。然而,假设我回到第一个解释器窗口并输入:

>>> fifo_write.write("some testing data\n")
>>> fifo_write.flush()

我本来期待的是,在第二个解释器中调用read会返回结果,我们能在屏幕上看到数据,但实际上并没有发生。如果我调用os.fsync,会出现以下情况:

>>> import os
>>> fifo_write.flush()
>>> os.fsync(fifo_write.fileno())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OSError: [Errno 22] Invalid argument

而FIFO的读取者仍然在等待。不过,如果我调用fifo_writer.close(),那么数据就会被刷新。如果我使用一个shell命令来给管道输入数据:

$ echo "some data" > fifo

那么读取者的输出是:

>>> fifo_read.read()
'some data\n'

有没有人遇到过这种情况?如果有,是否有解决办法?我当前的操作系统是Ubuntu 11.04,使用的是Linux 2.6.38。

2 个回答

9

为了避免需要刷新数据,可以在打开文件时不使用缓冲:

fifo_read = open('fifo', 'r', 0)

这样做会去掉高级缓冲。数据会直接发送到操作系统,因为这是一个FIFO(先进先出)队列,数据实际上不会写入磁盘,而是直接通过FIFO缓冲区传递给读取者,所以你不需要进行同步。

当然,你应该先用 os.mkfifo() 或者在命令行中使用 mkfifo 创建FIFO,如你在评论中提到的那样。

14

read() 这个函数不会返回,直到它读到文件的结束标志(EOF)。

你可以试着指定想要读取的字节数,比如 read(4)。不过,这个函数还是会一直等,直到有足够的字节被写入。所以,写数据的那一方必须至少写入你指定的字节数,然后再调用 flush() 来确保数据被发送出去。

撰写回答