Как правильно писать FIFO в Python?

Что-то очень странное происходит, когда я открываю FIFO (именованные каналы) в Python для записи. Рассмотрим, что происходит, когда я пытаюсь открыть 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_writer.close(), тогда данные будут сброшены. Если я использую команду оболочки для подачи канала:

$ echo "some data" > fifo

тогда вывод считывателя:

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

Кто-нибудь испытал это? Если это так обходное решение? Моя текущая ОС - Ubuntu 11.04 с Linux 2.6.38.

Ответы

Ответ 1

read() не возвращается, пока не достигнет EOF.

Вы можете попробовать указать количество прочитанных байтов, например read(4). Это будет продолжаться до тех пор, пока не будет записано достаточно байт, поэтому продюсер должен записать как минимум столько байтов, а затем вызвать flush().

Ответ 2

Чтобы избежать необходимости промывки, откройте файл без буферизации:

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

Это позволит удалить буферизацию высокого уровня. Данные поступают непосредственно в ОС и, будучи фиолетовыми, они никогда не записываются на диск, а передаются прямо читателю через буфер fifo, поэтому вам не нужно синхронизировать.

Конечно, вы должны были создать fifo сначала с os.mkfifo() или mkfifo в оболочке, как вы указали в комментарии.