【问题标题】:Use subprocess.communicate() to pipe stdin without waiting for process使用 subprocess.communicate() 来管道标准输入而不等待进程
【发布时间】:2016-03-02 22:15:31
【问题描述】:

我需要启动一个进程并将一个字符串输入标准输入,我目前正在这样做:

proc = subprocess.Popen(["MyCommandHere"], stdin=subprocess.PIPE)
proc.communicate(input=bytes(my_str_input + "\n", "ascii"))

问题是当我使用subprocess.communicate()时它是一个阻塞调用,等待进程退出。我不想等待。

有没有什么方法可以让communicate() 不被阻塞,或者有什么其他的方法来管道我的输入?我问的是非阻塞写入,而不是非阻塞读取。

【问题讨论】:

  • 我是在写,而不是在读
  • IANAPP,但也许在单独的进程中运行 proc.communicate 会起作用?
  • @bazza,如果有其他方法,我真的很讨厌这样做。

标签: python


【解决方案1】:

两个明显的选择:

  1. 使用单独的线程或进程
  2. 从临时文件馈送stdin

选项 1:

import threading

def send_data_to(proc, inp):
    proc.communicate(inp)

proc = subprocess.Popen(["MyCommandHere"], stdin=subprocess.PIPE)
threading.Thread(target=send_data_to, args=(proc, bytes(my_str_input + "\n", "ascii"))).start()

选项 2:

import tempfile

with tempfile.TemporaryFile() as tf:
    tf.write(bytes(my_str_input + "\n", "ascii"))
    tf.flush()
    tf.seek(0)  # Might not be needed
    proc = subprocess.Popen(["MyCommandHere"], stdin=tf)

对临时文件的写入可能会阻塞,但通常临时文件会由操作系统优化,以尽可能减少对磁盘的写入;如果该过程可能需要一些时间才能完成,您可能会直接阻塞太长的管道,但写出数据的小阻塞无关紧要。尽管 Python 在 with 块退出时关闭了临时文件(这通常会导致它被删除),但进程会维护它的句柄,防止它在进程完成之前被清理。

注意:所有这些都假设该过程可能不会在启动时立即完全消耗您的输入。如果进程基本上立即读取输入,然后完成所有工作,您可以简化为:

proc.stdin.write(bytes(my_str_input + "\n", "ascii"))
proc.stdin.close()  # Ensures the process knows nothing else is coming

如果进程一次消耗一点输入,并且输入大于管道缓冲区(因此您不能一次全部写入),这只会有阻塞的风险。

【讨论】:

  • 我讨厌创建另一个进程来简单地运行一个进程,而我想要管道的内容非常敏感,所以我想避免暂时将其写入磁盘。
  • a-ha...关键是proc.stdin.close() ...谢谢!
  • @gnychis:好吧,threading.Thread 的生成成本相当低,而且在某些操作系统上,未命名的TemporaryFile 实际上永远不会在磁盘上结束,但我同意你的观点。 .close() 绝对是当输入足够小以适合管道缓冲区和/或立即在子进程中消耗时的答案。
【解决方案2】:

看看at the docs on Popen.stdin。它只是一个标准的可写对象(而且,在大多数情况下,还是一个标准的文件句柄),所以你可以这样做:

proc.stdin.write(bytes(...))

无需等待子进程完成即可将数据写入标准输入。

【讨论】:

  • 这似乎对我不起作用。这样做后我什至尝试过 proc.stdin.flush()。
  • 你是对的,.close() 迫使它最终通过
  • 如果我打电话给close(),以后可以写标准输入吗?如果没有,我怎样才能正确刷新标准输入?
猜你喜欢
  • 2018-11-17
  • 2012-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-28
  • 1970-01-01
  • 2019-06-16
  • 1970-01-01
相关资源
最近更新 更多