使用子进程PIPE在Python脚本之间发送字符串

时间:2013-03-13 21:16:04

标签: python subprocess stdout stdin

我想在我的主python程序中使用subprocess打开一个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读取此字符串并将pickle数据发送到脚本2
  5. 然后......
  6. 主要问题是如何做2-4部分。然后应该遵循两个脚本之间的其余通信。截至目前,我只能在脚本2终止后才能读取它。

    非常感谢任何帮助。

    更新

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

2 个答案:

答案 0 :(得分:4)

管道的问题在于,如果您调用读取操作并且没有任何内容可读,则代码会停止,直到另一方写入您要阅读的内容为止。此外,如果你写得太多,你的下一个写操作可能会阻塞,直到另一方从管道读取内容并释放它。

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

无论如何,您需要设置某种协议。想想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()

答案 1 :(得分:0)

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

为了解决这个问题,我使用了picklepipe模块,它定义了一个通用对象序列化管道接口以及一个使用pickle协议PicklePipe的管道(也是一个使用的名为MarshalPipe的{​​{3}}协议。它可以发送的不仅仅是字符串,它可以将任何pickleable对象发送给它的同行。

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

支持Python 2.7+(可能是2.6)和所有主要平台。甚至可以在两个不同版本的Python之间发送对象!查看marshalproject documentation

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