web-dev-qa-db-ja.com

Python PIPEという名前の読み取り

Linuxに名前付きパイプがあり、pythonから読みたいです。問題は、pythonプロセスが1つのコア(100%)を継続的に「消費」することです。私のコードは次のとおりです。

FIFO = '/var/run/mypipe'
os.mkfifo(FIFO)
with open(FIFO) as fifo:
    while True:
        line = fifo.read()

「スリープ」が状況またはプロセスがパイプからの入力データの一部を失うのを助けるかどうかを尋ねたいです。入力を制御できないため、データ入力の頻度がわかりません。選択と投票について読みましたが、問題の例が見つかりませんでした。最後に、100%の使用がデータ入力に影響を与えるかどうか(損失か何か?).

編集:ループを破りたくない。プロセスを継続的に実行し、パイプからのデータを「聞く」ようにします。

8
user1005633

通常のUNIXの方法では、read(2)は0バイトを返し、ファイルの終わりを示します。

  • ファイルにもうバイトがありません
  • ソケットのもう一方の端が接続をシャットダウンしました
  • 作家はパイプを閉じました

あなたの場合、ライターがファイル記述子を閉じているため、fifo.read()は空の文字列を返します。

その場合を検出し、ループから抜け出す必要があります。

reader.py

import os
import errno

FIFO = 'mypipe'

try:
    os.mkfifo(FIFO)
except OSError as oe: 
    if oe.errno != errno.EEXIST:
        raise

print("Opening FIFO...")
with open(FIFO) as fifo:
    print("FIFO opened")
    while True:
        data = fifo.read()
        if len(data) == 0:
            print("Writer closed")
            break
        print('Read: "{0}"'.format(data))

セッション例

ターミナル1

$ python reader.py 
Opening FIFO...
<blocks>

ターミナル2

$ echo -n 'hello' > mypipe 

ターミナル1

FIFO opened
Read: "hello"
Writer closed
$ 

更新1-継続的に再度開く

おそらくライターが閉じた後でも、パイプ上の書き込みをリッスンし続けることを示します。

これを効率的に行うために、次の事実を利用できます(そして利用すべきです)。

通常、もう一方の端も開かれるまでFIFOブロックを開きます。

ここでは、openreadループの周りに別のループを追加します。この方法では、パイプが閉じられると、コードはパイプを再度開こうとしますが、別のライターがパイプを開くまでブロックされます。

import os
import errno

FIFO = 'mypipe'

try:
    os.mkfifo(FIFO)
except OSError as oe:
    if oe.errno != errno.EEXIST:
        raise

while True:
    print("Opening FIFO...")
    with open(FIFO) as fifo:
        print("FIFO opened")
        while True:
            data = fifo.read()
            if len(data) == 0:
                print("Writer closed")
                break
            print('Read: "{0}"'.format(data))

ターミナル1

$ python reader.py 
Opening FIFO...
<blocks>

ターミナル2

$ echo -n 'hello' > mypipe 

ターミナル1

FIFO opened
Read: "hello"
Writer closed
Opening FIFO...
<blocks>

ターミナル2

$ echo -n 'hello' > mypipe 

ターミナル1

FIFO opened
Read: "hello"
Writer closed
Opening FIFO...
<blocks>

... 等々。


パイプのmanページを読むと、さらに学ぶことができます。

21

(後年)for ... in ...を使用してOPのユースケースを理解している場合、まさに望みどおりになります。

import os

FIFO = 'myfifo'
os.mkfifo(FIFO)
with open(FIFO) as fifo:
    for line in fifo:
        print(line)

このプログラムは、提供されるまでfifoからの入力を辛抱強く待ってから、画面に出力します。その間、CPUは使用されません。

これはPythonのより慣用的な方法でもあるため、read()を直接使用するよりもお勧めします。

クライアント側がfifoへの書き込みを閉じると、forループが終了し、プログラムが終了します。 fifoを再度開き、次のクライアントが開くのを待つ場合は、forセクションをwhileループに入れることができます。

import os

FIFO = 'myfifo'
os.mkfifo(FIFO)
while True:
    with open(FIFO) as fifo:
        for line in fifo:
            print(line)

これにより、FIFOが再び開き、通常どおりに待機します。

0
Tristan