Python读取命名管道

2024-05-19 14:43:56 发布

您现在位置:Python中文网/ 问答频道 /正文

我在linux中有一个命名管道,我想从python中读取它。问题是python进程持续“消耗”一个核心(100%)。我的代码如下:

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

我想问一下“睡眠”是否有助于解决这个问题,或者进程会丢失管道中的一些输入数据。我无法控制输入,所以我不知道数据输入的频率。我读到了select和poll,但没有找到任何问题的例子。最后,我想问一下100%的使用是否会对数据输入产生任何影响(丢失或什么?)。

编辑:我不想打破这个循环。我希望进程持续运行,并“听到”来自管道的数据。


Tags: 数据run代码核心管道进程osvar
2条回答

在典型的UNIX方式中,read(2)返回0字节以指示文件结尾,这可能意味着:

  • 文件中没有更多字节
  • 套接字的另一端已关闭连接
  • 作者已关闭了一个管道

在您的例子中,fifo.read()返回一个空字符串,因为编写器已关闭其文件描述符。

你应该发现这种情况并跳出你的圈子:

读卡器.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-持续重新打开

您表示希望继续监听管道上的写入,甚至可能在写入程序关闭之后。

为了有效地做到这一点,你可以(而且应该)利用以下事实

Normally, opening the FIFO blocks until the other end is opened also.

在这里,我在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页了解更多信息:

(几年后)如果我正在使用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并像往常一样等待。

相关问题 更多 >