【问题标题】:Continuous communication between parent and child subprocess in Python (Windows)?Python(Windows)中父子进程之间的持续通信?
【发布时间】:2020-06-26 01:51:24
【问题描述】:

我有这个脚本:

import subprocess

p = subprocess.Popen(["myProgram.exe"],
                     stdin=subprocess.PIPE,
                     stdout=subprocess.PIPE)
while True:
    out, _ = p.communicate(input().encode())
    print(out.decode())

在我得到第二个输入之前工作正常:

ValueError: Cannot send input after starting communication

有没有办法在 Windows 中的父子进程之间发送多条消息?

[编辑]
我无权访问myProgram.exe的源代码
它是一个从查询返回结果的交互式命令行应用程序
运行 >> myProgram.exe < in.txt > out.txtin.txt 一起工作正常:

query1;
query2;
query3;

【问题讨论】:

  • 将对p.communicate()的调用放在循环上方。
  • @Todd 我试过了。但是这只允许我只发送一条消息。
  • 这就是函数文档的说明。您只能发送一次。也许还有另一种使用另一种方法进行交互的方式。
  • @Todd 是的,这就是我要的 :)
  • 好的@entropyfeverone,我能够模拟类似于您的用例的设置并让它工作。我更新了答案。告诉我进展如何。

标签: python-3.x subprocess stdin communication popen


【解决方案1】:

通过 stdin/stdout 与另一个正在运行的进程交互

为了模拟 Python 脚本启动命令行交互式进程并通过 stdin/stdout 发送/接收文本的用例,我们有一个主脚本,它启动另一个运行简单交互式循环的 Python 进程。

这也适用于 Python 脚本需要启动另一个进程并在输入时读取其输出而没有任何交互性的情况。

主脚本

import subprocess
import threading
import queue
import time

if __name__ == '__main__':

    def enqueue_output(outp, q):
        for line in iter(outp.readline, ''):
            q.put(line)
        outp.close()

    q = queue.Queue()

    p = subprocess.Popen(["/usr/bin/python", "/test/interact.py"],
                         stdin    = subprocess.PIPE,
                         stdout   = subprocess.PIPE,
                         # stderr   = subprocess.STDOUT,
                         bufsize  = 1,
                         encoding ='utf-8')

    th = threading.Thread(target=enqueue_output, args=(p.stdout, q))
    th.daemon = True

    th.start()

    for i in range(4):

        print("dir()", file=p.stdin)

        print(f"Iteration ({i}) Parent received: {q.get()}", end='')
        # p.stdin.write("dir()\n")
        # while q.empty():
        #     time.sleep(0)
        # print(f"Parent: {q.get_nowait()}")

interact.py 脚本

if __name__ == '__main__':

    for i in range(2):

        cmd = raw_input()

        print("Iteration (%i) cmd=%s" % (i, cmd))

        result = eval(cmd)

        print("Iteration (%i) result=%s" % (i, str(result)))

输出

Iteration (0) Parent received: Iteration (0) cmd=dir()
Iteration (1) Parent received: Iteration (0) result=['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'cmd', 'i']
Iteration (2) Parent received: Iteration (1) cmd=dir()
Iteration (3) Parent received: Iteration (1) result=['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'cmd', 'i', 'result']

此问答用于模拟来自目标进程的非阻塞读取:https://stackoverflow.com/a/4896288/7915759

该方法提供了一种在主线程中不阻塞地检查输出的方法; q.empty() 会告诉你是否没有数据。您也可以使用q.get() 或超时q.get(2) 来处理阻塞呼叫 - 参数是秒数。它可以是小于零的浮点值。

进程之间基于文本的交互可以在没有线程和队列的情况下完成,但是这个实现提供了更多关于如何检索返回的数据的选项。

Popen() 参数,bufsize=1encoding='utf-8' 可以使用主脚本中的<stdout>.readline(),并将编码设置为两个进程都可以理解的 ascii 兼容编解码器(1 不是缓冲区的大小,这是一个表示行缓冲的符号值)。

使用此配置,两个进程可以简单地使用print() 相互发送文本。此配置应该兼容许多基于交互式文本的命令行工具。

【讨论】:

  • 不,它没有。我使用了input().encode(),因为我只使用input() 就出错了,但它又没有打印任何东西。
  • 是否有命令行选项可以做到这一点?我无权访问myProgram.exe的源代码
  • 没有成功 :( 我不明白为什么没有这样的例子。我的意思是,当我在命令行>myProgram.exe < in.txt > out.txt 中写入时,它执行得很好,从in.txt 和输出到out.txt。然而,由于某种原因,使用python脚本以更流式的方式实现这种行为更加困难。
  • 我做到了,由于某种原因,它只显示一次我输入的内容。在那之后,我必须打断然后显示我输入的内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-19
  • 2018-07-18
  • 1970-01-01
  • 2012-04-15
  • 1970-01-01
  • 2017-07-22
相关资源
最近更新 更多