web-dev-qa-db-ja.com

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()
_

予想される動作は、2番目のインタープリターで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'
_

誰かがこれを経験しましたか?もしそうなら、それに対する回避策はありますか?私の現在のOSはLinux2.6.38を搭載したUbuntu11.04です。

18

read()は、EOFに達するまで戻りません。

read(4)のように、読み取りたいバイト数を指定してみてください。これは、十分なバイトが書き込まれるまでブロックされるため、プロデューサーは少なくともそのバイト数を書き込んでから、flush()を呼び出す必要があります。

10
Marcelo Cantos

フラッシュの必要性を回避するには、バッファリングせずにファイルを開きます。

_fifo_read = open('fifo', 'r', 0)
_

これにより、高レベルのバッファリングが削除されます。データはOSに直接送られ、FIFOであるため、実際にディスクに書き込まれることはありませんが、FIFOバッファーを介してリーダーに直接渡されるため、同期する必要はありません。

もちろん、コメントで指摘したように、シェルでos.mkfifo()またはmkfifoを使用して最初にFIFOを作成する必要があります。

3
Mike