使用管道时 open() 与 os.open() 的行为

Behaviour of open() vs os.open() when using pipes

我一直在为写作和阅读管道而苦苦挣扎。问题是,一方面我通过 open() 获得的文件对象处理管道。另一方面,我使用的是 "low-level" os.open() 获得的文件描述符。虽然看起来很相似,但代码的行为却大不相同,我真的不明白为什么。

我举了一个小例子。我正在改变写入 pipe.In write_1.py 的方法,我使用 os.open() 并且一切都按预期工作。在 write_2.py 中使用 open() ,当从管道读取时我得到一个 EAGAIN-error 并且只有在书写端最后用pipe.close()关闭了。

两种情况的阅读方式相同,参见read.py。 你能解释一下不同的行为吗?

(Python 版本 3.5.2)

文件

# write_1.py
import os
import errno
import time

bufferSize = 100
PATH = "pipe"
i = 0

pipe = os.open(PATH, os.O_WRONLY | os.O_NONBLOCK)

while i < 20:
    i +=1
    my_str = "written {0}-times".format(i)
    try:
        input = os.write(pipe, my_str.encode())
    except OSError as err:
        if err.errno == 11:
            print("error 11")
            continue
        else:
            raise err
    if input:
        print("written {0} chars ".format(input))
    print("Sleep 500 ms")
    time.sleep(0.5)

os.close(pipe)
# write_2.py
import os
import errno
import time

bufferSize = 100
PATH = "pipe"
i = 0

pipe = open(PATH, "w")
fd = pipe.fileno()
fl = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)

while i < 20:
    i +=1
    my_str = "written {0}-times".format(i)
    try:
        input = pipe.write(my_str)
    except OSError as err:
        if err.errno == 11:
            print("error 11")
            continue
        else:
            raise err
    if input:
        print("written {0} chars ".format(input))
    print("Sleep 500 ms")
    time.sleep(0.5)

pipe.close()

# read.py
import os
import errno
import time

bufferSize = 100
PATH = "pipe"
i = 0

pipe = os.open(PATH, os.O_RDONLY | os.O_NONBLOCK)

while i < 100:
    i +=1
    try:
        input = os.read(pipe, bufferSize)
    except OSError as err:
        if err.errno == 11:
            print("error 11")
            print("Sleep 500 ms")
            time.sleep(0.5)
            continue
        else:
            raise err
    if input:
        print(input)
    print("Sleep 500 ms")
    time.sleep(0.5)

os.close(pipe)

使用 open,您已接受默认缓冲设置(通过不提供 buffering 参数),因此您将获得一个缓冲文件对象。此缓冲区独立于任何 OS 级缓冲。

使用 os.open,没有文件对象,也没有文件对象级缓冲。

(此外,您使用 open 在阻塞 I/O 模式下打开管道,但这不是造成您所看到的差异的原因。)