为什么 select.select 告诉我它不可读

Why is select.select telling me it is not readable

以下最小代码的行为似乎不正确。为什么第二个 select.select 找不到剩余的行。某处是否有缓冲以及如何公开正确的缓冲区?

import select
import os

read, write = os.pipe()
writeable = os.fdopen(write, "w")
readable = os.fdopen(read, "r")
writeable.write("first\n")
writeable.write("second\n")
writeable.flush()
if select.select([readable], [], [], 10)[0][0] == readable:
    print(readable.readline())

print(str(select.select([readable], [], [], 1)))
print(readable.readline())

--- 结果:

first

([], [], [])
second

问题是由于缓冲。我找不到任何具体的文档,但当您第一次调用 readline.

时,看起来完整的输入已被拉入缓冲区

您可以指定无缓冲作为 fdopen 中的第三个变量,但不允许用于文本,throwing

ValueError: can't have unbuffered text I/O

如果您将输入设为允许无缓冲 I/O 的字节流,您可以看到差异(更改标记有注释):

import select
import os

read, write = os.pipe()

# Use a byte stream and add 0 to disable buffering
writeable = os.fdopen(write, "wb", 0)
readable = os.fdopen(read, "rb", 0)

# Write in bytes
writeable.write(b"first\n")
writeable.write(b"second\n")
writeable.flush()

if select.select([readable], [], [], 10)[0][0] == readable:
    print(readable.readline())

print(str(select.select([readable], [], [], 1)))
print(readable.readline())

# Do another check on select.
print(str(select.select([readable], [], [], 1)))

这样做会给我们一个输出:

>>>b'first\n'
>>>([<_io.FileIO name=4 mode='rb' closefd=True>], [], [])
>>>b'second\n'
>>>([], [], [])

我猜这就是您所期望的行为,如果您随后从 fdopen 调用中删除禁用缓冲 0 变量,

writeable = os.fdopen(write, "wb")
readable = os.fdopen(read, "rb")

你回来了:

>>>b'first\n'
>>>([], [], [])
>>>b'second\n'
>>>([], [], [])

与您原来的示例一样。