如何在Python中正确写入FIFO?
在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()
来确保数据被发送出去。