Python:os.read()在fd上阻塞

时间:2013-12-08 19:07:14

标签: python linux

如果fd是bash shell,如何避免行缓冲问题?

2 个答案:

答案 0 :(得分:1)

以下是我从您的问题和评论中理解的内容以及答案结尾处不满意的解决方法的摘要。摘要应该帮助其他人回答您的问题。

似乎你有一个程序(非python)想要执行可能需要tty(Q: Why not just use a pipe (popen())?)的任意shell命令,并且你已选择作为执行运行{{1写入/读取其stdin / stdout。

现在你遇到一个问题,你无法找到shell命令的输出结束,即,你不知道何时停止阅读pty.spawn("/bin/sh", read_callback)标准输出,如果你试着阅读太多,那么你的非python程序块。

首先,program.py 中的os.read不会阻止。它可能返回少于1024个字节,但它不会阻塞:

read_callback

虽然在父程序尝试阅读时没有帮助。

解决方法

为避免阻止读取,父级可以将运行def read_callback(fd): data = os.read(fd, 1024) # <-- this doesn't block return data 中的PS1环境更改为某个唯一值,或者在每个命令后注入sh。然后它可以一次读取一个字节,直到它读取echo something_unique。它应该停在这一点上。

作为替代方法,您可以尝试在父级中使管道非阻塞,并一次读取多个字节。或者使用定义明确消息边界的交换协议并逐个运行shell命令,例如,使用something_unique(在Python端轻松检测输出结束)。

答案 1 :(得分:0)

这似乎有效:

#!/usr/local/cpython-3.3/bin/python

import os
import pty
#mport sys
import fcntl

OFLAGS = None

def set_nonblocking(file_handle):
    """Make a file_handle non-blocking."""
    global OFLAGS
    OFLAGS = fcntl.fcntl(file_handle, fcntl.F_GETFL)
    nflags = OFLAGS | os.O_NONBLOCK
    fcntl.fcntl(file_handle, fcntl.F_SETFL, nflags)


def main():
    (pid, file_handle) = pty.fork()
    if pid == 0:
        # we're in the child
        os.execl('/bin/sh', '/bin/sh', '-i')
    else:
        #file_handle = os.open('/dev/null', os.O_RDONLY)
        set_nonblocking(file_handle)
        while True:
            try:
                # return 1-n bytes or exception if no bytes
                data = os.read(file_handle, 1024)
            except BlockingIOError:
                #sys.stdout.write('no data read\r')
                pass
            else:
                print(len(data), data)

main()

有时处理非阻塞I / O的方法是使用线程或子进程,BTW。然后一个线程或子进程可以阻塞,而其他线程或子进程可以快乐地完成它们的工作。

HTH