Mac OS中{_44}上O_NONBLOCK fifo上大写的性能不佳

时间:2018-02-14 11:27:16

标签: python macos io fifo

我在FIFO上有一个读写器,读者不能无限期地阻塞。为此,我使用O_NONBLOCK打开阅读结束。

写端可以阻塞,因此我将其作为常规文件打开。大写无法接受非常 - 读取/写入4MB块需要几分钟而不是预期的一秒钟(预期,因为在linux中相同的代码只需要几分之一秒)。

Python中复制问题的示例代码。首先,使用mkfifo创建一个fifo,例如mkfifo some_fifo,然后运行阅读结束,然后是写作结束。

阅读结束:

import os, time
# mkfifo some_fifo before starting python
fd = os.open('some_fifo',os.O_RDONLY | os.O_NONBLOCK)
while True:
    try:
        read = len(os.read(fd, 8192)) # read up to 8kb (FIFO buffer size in mac os)
        print(read)
        should_block = read < 8192 # linux
    except BlockingIOError:
        should_block = True # mac os
    if should_block:
        print('blocking')
        time.sleep(0.5)

写完:

import os
fd = os.open('some_fifo',os.O_WRONLY)
os.write(fd, b'aaaa'*1024*1024) # 4MB write

注意:我遇到此问题的原始代码是也在linux上运行的跨平台Java代码。不幸的是,这意味着我不能将kqueue与kevent的data字段一起使用来计算出我可以在不阻塞的情况下读取多少内容 - 这些数据在我使用的epoll / kqueue的抽象中丢失了。这意味着使用阻塞fd à la this answer的解决方案是不可接受的。

编辑:原始代码使用kqueue来阻止读取端的文件描述符,执行更糟

编辑2 :Linux os.read()在连接管道的另一端之前没有抛出BlockingIOError,尽管文档声明它应该(调用成功(返回0)但是将errno设置为EAGAIN)。更新了代码以便对linux行为友好。

编辑3 :macOS的代码最初是:

import select, os
# mkfifo some_fifo before starting python
fd = os.open('some_fifo',os.O_RDONLY | os.O_NONBLOCK)
kq = select.kqueue()
ke = select.kevent(fd)
while True:
    try:
        read = len(os.read(fd, 8192)) # read up to 8kb (FIFO buffer size in mac os)
    except BlockingIOError:
        evts = kq.control([ke], 1, 10) # 10-second timeout, wait for 1 event
        print(evts)

这与具有睡眠的版本一样糟糕,但是睡眠确保问题不在于阻塞机制,而且是跨平台的。

0 个答案:

没有答案