Как правильно писать 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
в оболочке, как вы указали в комментарии.