Python select() 行为很奇怪

发布于 2024-11-07 09:23:34 字数 964 浏览 0 评论 0原文

我在理解 select.select 的行为时遇到一些困难。请考虑以下 Python 程序:

def str_to_hex(s):
    def dig(n):
        if n > 9:
            return chr(65-10+n)
        else:
            return chr(48+n)
    r = ''
    while len(s) > 0:
        c = s[0]
        s = s[1:]
        a = ord(c) / 16
        b = ord(c) % 16
        r = r + dig(a) + dig(b)
    return r

while True:
    ans,_,_ = select.select([sys.stdin],[],[])
    print ans
    s = ans[0].read(1)
    if len(s) == 0: break
    print str_to_hex(s)

我已将其保存到文件“test.py”中。如果按如下方式调用它:

echo 'hello' | ./test.py

那么我会得到预期的行为: select 永远不会阻塞并且所有数据都会被打印;然后程序终止。

但如果我以交互方式运行该程序,我会得到最不希望的行为。请考虑以下控制台会话:

$ ./test.py
hello
[<open file '<stdin>', mode 'r' at 0xb742f020>]
68

然后程序挂在那里; select.select 现在再次阻塞。直到我提供更多输入或关闭输入流后,才会打印下一个字符(以及所有其余字符),即使已经有字符在等待!谁能向我解释这种行为?我在我编写的流隧道程序中看到类似的东西,它破坏了整个事件。

感谢您的阅读!

I'm having some trouble understanding the behavior of select.select. Please consider the following Python program:

def str_to_hex(s):
    def dig(n):
        if n > 9:
            return chr(65-10+n)
        else:
            return chr(48+n)
    r = ''
    while len(s) > 0:
        c = s[0]
        s = s[1:]
        a = ord(c) / 16
        b = ord(c) % 16
        r = r + dig(a) + dig(b)
    return r

while True:
    ans,_,_ = select.select([sys.stdin],[],[])
    print ans
    s = ans[0].read(1)
    if len(s) == 0: break
    print str_to_hex(s)

I have saved this to a file "test.py". If invoke it as follows:

echo 'hello' | ./test.py

then I get the expected behavior: select never blocks and all of the data is printed; the program then terminates.

But if I run the program interactively, I get a most undesirable behavior. Please consider the following console session:

$ ./test.py
hello
[<open file '<stdin>', mode 'r' at 0xb742f020>]
68

The program then hangs there; select.select is now blocking again. It is not until I provide more input or close the input stream that the next character (and all of the rest of them) are printed, even though there are already characters waiting! Can anyone explain this behavior to me? I am seeing something similar in a stream tunneling program I have written and it's wrecking the entire affair.

Thanks for reading!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

月棠 2024-11-14 09:23:34

sys.stdinread 方法工作在比 select 更高的抽象级别上。当您执行 ans[0].read(1) 时,Python 实际上会从操作系统读取大量字节并在内部缓冲它们。 select 不知道这种额外的缓冲;它只看到所有内容都已被读取,因此将阻塞,直到 EOF 或更多输入到达。您可以通过运行诸如 strace -e read,select python yourprogram.py 之类的命令来观察此行为。

一种解决方案是将 ans[0].read(1) 替换为 os.read(ans[0].fileno(), 1)os.read 是一个较低级别的接口,它和操作系统之间没有任何缓冲,因此它更适合 select

或者,使用 -u 命令行选项运行 python 似乎也会禁用额外的缓冲。

The read method of sys.stdin works at a higher level of abstraction than select. When you do ans[0].read(1), python actually reads a larger number of bytes from the operating system and buffers them internally. select is not aware of this extra buffering; It only sees that everything has been read, and so will block until either an EOF or more input arrives. You can observe this behaviour by running something like strace -e read,select python yourprogram.py.

One solution is to replace ans[0].read(1) with os.read(ans[0].fileno(), 1). os.read is a lower level interface without any buffering between it and the operating system, so it's a better match for select.

Alternatively, running python with the -u commandline option also seems to disable the extra buffering.

Bonjour°[大白 2024-11-14 09:23:34

它正在等待您发出 EOF 信号(交互使用时可以使用 Ctrl+D 来执行此操作)。您可以使用 sys.stdin.isatty() 来检查脚本是否正在交互运行,并相应地处理它,使用 raw_input 代替。我还怀疑您是否需要使用 select.select ,为什么不只使用 sys.stdin.read 呢?

if sys.stdin.isatty():
    while True:
        for s in raw_input():
            print str_to_hex(s)
else:
    while True:
        for s in sys.stdin.read(1):
            print str_to_hex(s)

这使得它既适合交互式使用,又适合流处理。

It's waiting for you to signal EOF (you can do this with Ctrl+D when used interactively). You can use sys.stdin.isatty() to check if the script is being run interactively, and handle it accordingly, using say raw_input instead. I also doubt you need to use select.select at all, why not just use sys.stdin.read?

if sys.stdin.isatty():
    while True:
        for s in raw_input():
            print str_to_hex(s)
else:
    while True:
        for s in sys.stdin.read(1):
            print str_to_hex(s)

Which would make it appropriate for both interactive use, and for stream processing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文