【问题标题】:Sending strings between to Python Scripts using subprocess PIPEs使用子进程 PIPE 在 Python 脚本之间发送字符串
【发布时间】:2013-03-02 01:20:11
【问题描述】:

我想在我的主 python 程序中使用子进程打开一个 Python 脚本。我希望这两个程序能够在它们都在运行时相互聊天,这样我就可以监控从脚本中的活动,即我需要它们在彼此之间发送字符串。

主程序将有一个类似的功能,将与从属脚本进行通信和监控:

脚本 1

import subprocess
import pickle
import sys
import time
import os

def communicate(clock_speed, channel_number, frequency):
    p = subprocess.Popen(['C:\\Python27\\pythonw','test.py'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    data = pickle.dumps([clock_speed, channel_number, frequency]).replace("\n", "\\()")
    print data
    p.stdin.write("Start\n")
    print p.stdout.read()
    p.stdin.write(data + "\n")
    p.poll()
    print p.stdout.readline()
    print "return:" + p.stdout.readline()
    #p.kill()

if __name__ == '__main__':
    print "GO"
    communicate(clock_speed = 400, channel_number = 0, frequency = 5*1e6)

test.py 脚本如下所示:

脚本 2

import ctypes
import pickle
import time
import sys

start = raw_input("")
sys.stdout.write("Ready For Data")
data = raw_input("")
data = pickle.loads(data.replace("\\()", "\n"))
sys.stdout.write(str(data))
###BUNCH OF OTHER STUFF###

我希望这些脚本执行以下操作:

  1. 脚本 1 使用 Popen 打开脚本 2
  2. 脚本 1 发送字符串“Start\n”
  3. 脚本 2 读取此字符串并发送字符串“Ready For Data”
  4. 脚本 1 读取此字符串并将腌制数据发送到脚本 2
  5. 那么无论如何...

主要问题是如何做第 2-4 部分。然后应该遵循两个脚本之间的其余通信。到目前为止,我只能在脚本 2 终止后读取字符串。

非常感谢任何帮助。

更新:

脚本 1 必须使用 32 位 Python 运行,而脚本 2 必须使用 64 位 Python 运行。

【问题讨论】:

  • 你能用multiprocessing module 来在supbrocesses中运行python吗
  • 我之所以使用子进程是因为我需要第二个脚本使用 64 位 Python 运行,而主脚本在 32 位 Python 中运行。这是驱动程序问题。我不认为多处理允许这样做。
  • 我认为我在 python 中运行的线程池和每个线程与一些 node.js 工作人员“通信”时遇到了类似的问题——对我有用的是flush()每个@987654326 之后的标准输出@ 否则,缓冲会延迟所有内容,直到流关闭。
  • 它允许调用其他机器所以可能docs.python.org/2/library/…

标签: python subprocess stdout stdin


【解决方案1】:

我也遇到了类似的问题,没有办法在不同进程之间发送通用 Python 对象,而不会遇到知道对方何时没有发送对象或关闭的问题。还尝试使用multiprocessing.Queue 通常意味着该进程需要由当前进程启动,而当两个进程想要协作时,情况并非总是如此。

为了解决这个问题,我使用了picklepipe 模块,它定义了一个通用对象序列化管道接口以及一个使用pickle 协议的管道,称为PicklePipe(也是一个使用marshal 协议的管道,称为MarshalPipe)。它不仅可以发送字符串,还可以将任何可腌制对象发送给它的对等体。

管道甚至是可选择的,这意味着当准备接收新对象时,selectors 模块(或selectors2、selectors34)可以将它们用作文件对象。这使得等待许多不同的管道准备好非常有效。

支持 Python 2.7+(可能还有 2.6)和所有主要平台。甚至可以在两个不同版本的 Python 之间发送对象!查看project documentation 或view the source on Github。

披露:我是picklepipe 的作者。我很想听听您的反馈。 :)

【讨论】:

    【解决方案2】:

    管道的问题是,如果你调用了一个读操作并且没有什么要读的,你的代码就会停滞不前,直到对方写了一些东西让你读。另外,如果你写的太多,你的下一个写操作可能会阻塞,直到对方从管道中读取一些东西并释放它。

    您可以进行“非阻塞调用”,在这些情况下将返回错误而不是阻塞,但您的应用程序仍需要明智地处理错误。

    无论如何,您都需要设置某种协议。想想 HTTP 或您熟悉的任何其他协议:有请求和响应,当您阅读两者中的任何一个时,协议总是会告诉您是否需要阅读其他内容。这样,您始终可以就是否等待更多数据做出明智的决定。

    这是一个有效的例子。它之所以有效,是因为有以下协议:

    • p1 发送一行,以 '\n' 结尾;
    • p2 也一样;
    • p1 发送另一行;
    • p2 也一样;
    • 两人都很高兴并退出。

    为了向管道(在任一侧)写入一行并确保它进入管道,我调用write(),然后调用flush()。

    为了从管道(在任一侧)读取一行但不超过一个字节,从而阻塞我的代码,直到该行准备好并且不再超过此时间,我使用readline()。

    您可以进行其他调用和其他协议,包括现成的,但单行协议适用于简单的事情和像这样的演示。

    p1.py:

    import subprocess
    
    p = subprocess.Popen(['python', 'p2.py'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    p.stdin.write("Hello\n")
    p.stdin.flush()
    print 'got', p.stdout.readline().strip()
    p.stdin.write("How are you?\n")
    p.stdin.flush()
    print 'got', p.stdout.readline().strip()
    

    p2.py:

    import sys
    
    data = sys.stdin.readline()
    sys.stdout.write("Hm.\n")
    sys.stdout.flush()
    data = sys.stdin.readline()
    sys.stdout.write("Whatever.\n")
    sys.stdout.flush()
    

    【讨论】:

    • Windows 上"\n" 可能存在问题:.readline() 是否理解另一端产生的换行符(b"\n" b"\r\n" 转换)。
    • 优秀的答案。谢谢你。此外,“\n”对我来说适用于 Windows(以防万一阅读本文以供参考的人担心这个问题)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多