python - 如何从 `stdin` 创建非阻塞连续读取?

标签 python python-3.x subprocess stdin nonblocking

我有一个进程,它是这样创建的:

p = subprocess.Popen(args   = './myapp',
                     stdin  = subprocess.PIPE,
                     stdout = subprocess.PIPE,
                     universal_newlines=True)

稍后,我尝试写入 pstdin:

p.stdin.write('my message\n')

myapp 进程具有以下设置:

q = queue.Queue()
def get_input():
    for line in iter(sys.stdin.readline, ''):
        q.put(line)
    sys.stdin.close()

threading.Thread(name   = 'input-getter',
                 target = get_input).start()

它正在尝试连续读取新行,如下所示:

try:
    print('input:', q.get_nowait())
except Empty:
    print('no input')

不幸的是,子进程从未收到我的任何消息。当然,当我使用:

p.communicate('my message\n')

子进程收到消息,但正如预期的那样,communicate 方法关闭了 pstdin,因此没有更多的通信进行上。

最佳答案

p = subprocess.Popen(args   = './myapp',
                     stdin  = subprocess.PIPE,
                     stdout = subprocess.PIPE,
                     universal_newlines=True)

while p.poll() is None:
    data = p.stdout.readline()

这将创建一个非阻塞的进程读取,直到进程退出。 但是,这里有一些注意事项需要注意。例如,如果您也通过管道传输 stderr,但不从中读取...那么您很可能会填充一两个缓冲区,并且无论如何都会挂起程序。因此,请始终确保在手动执行操作时清除所有缓冲区 I/O。

如果可能的话,一个更好的选择是使用 select.epoll(),这只在 unix 系统上可用,但会给你带来更好的性能和错误处理:)

epoll = select.epoll()
epoll.register(p.stdout.fileno(), select.EPOLLHUP) # Use select.EPOLLIN for stdin.

for fileno, event in epoll.poll(1):
    if fileno == p.stdout.fileno():
        # ... Do something ...

注意:请记住,每当进程需要输入时,它通常会通过 stdout 进行指示,因此您仍然需要使用 STDOUT 注册 select.epoll 以检查“等待输入”。您可以注册 select.EPOLLIN 以检查是否提供了输入,但我几乎不明白这一点,因为请记住,这就是您选择输入到您应该已经知道的过程的内容是“正在发生的”。

检查进程是否需要输入

您可以使用 select.epoll 来检查进程是否正在等待输入,而不会在上面的示例中阻止您的应用程序执行。但还有更好的选择。

Pexpect是一个做得非常好的库,例如与 SSH 一起工作。

它的工作方式与子流程略有不同,但可能是一个不错的选择。

让 subprocess.popen 与 SSH 一起工作

如果这是您想要的,我将重定向到另一个问题+答案(因为 SSH 将以 protected 方式生成 stdin

Python + SSH Password auth (no external libraries or public/private keys)?

关于python - 如何从 `stdin` 创建非阻塞连续读取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30217916/

相关文章:

python - 如何通过 Python 中的 Google Sheets API v4 调用电子表格中的特定工作表

python - 使用subprocess.popen SSH,无法输入密码

python - 为什么 `subprocess.Popen` 向 shell 返回不同的输出? - window

Python AST 到字典结构

python - 更改 Windows XP 上的默认 Python 解释器

python - reduce() 有什么问题?

python - 在 Python 中通过服务器与可执行文件交互?

Python virtualenv 安装 scipy

python - Chrome 和 Firefox 中的 session 处理

javascript - Python 列表到 django javascript 作为文本