Как правильно писать в 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 все еще ждет. Однако, если я вызову fifo_writer.close(), данные будут сброшены. Если я использую команду оболочки для подачи канала:

$ echo "some data" > fifo

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

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

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


person Thiago de Arruda    schedule 13.08.2011    source источник
comment
используйте либо os.mkfifo('fifo'), либо в оболочке mkfifo fifo   -  person Thiago de Arruda    schedule 13.08.2011
comment
fsync() по FIFO не имеет смысла; никакие данные не сохраняются на диске (кроме может быть в свопе в очень странных ситуациях).   -  person Ignacio Vazquez-Abrams    schedule 13.08.2011


Ответы (2)


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

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

person Marcelo Cantos    schedule 13.08.2011
comment
Спасибо за это, добавление аргумента к методу «чтения» решило проблему, хотя все еще необходимо очистить. - person Thiago de Arruda; 13.08.2011
comment
@ThiadodeArruda, какой именно аргумент? - person n611x007; 28.10.2014
comment
@ n611x007: я предполагаю количество байтов для чтения, как в примере. Это единственный задокументированный параметр read(). - person bjhend; 18.07.2019

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

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

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

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

person Mike    schedule 06.09.2013