2013-03-13 88 views
3

我想在我的主python程序中使用子进程打开一个Python脚本。我希望这两个程序能够彼此聊天,因为它们都在运行,所以我可以监视从脚本中的活动,即我需要它们在彼此之间发送字符串。使用子进程PIPE在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
  3. 脚本1将字符串“开始\ n”
  4. 脚本2读取此字符串和发送串“准备好进行数据”
  5. 脚本1读取这个串和酸洗数据发送到脚本2
  6. 然后无论...

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

任何帮助,非常感谢。

UPDATE:

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

+0

您可以使用[multiprocessing模块](http://docs.python.org/3/library/multiprocessing.html),它被设计成在supbrocesses中运行python – Mark 2013-03-13 21:36:27

+0

我之所以使用子进程是因为我需要使用64位Python运行第二个脚本,而主脚本运行在32位Python中。这是一个驱动程序问题。我不认为多处理允许这样做。 – Mink 2013-03-13 21:39:35

+0

我想我有一个类似的问题,在python中运行一个线程池,每个线程都与某个node.js工作程序“通信” - 对我来说什么工作是在每个write()之后flush()'stdout,否则,缓冲推迟了一切,直到溪流关闭。 – nvlass 2013-03-13 21:49:07

回答

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() 
+0

在Windows上可能有''\ n“'问题:是否'.readline()'理解另一端产生的换行符('b'\ n“'<-->'b”\ r \ n“'转换)。 – jfs 2013-03-14 02:28:17

+1

优秀的答案。谢谢。此外,“\ n”适用于我的Windows(如果有人阅读本文以供参考,则担心此问题)。 – Mink 2013-03-15 18:01:58

0

我也有过类似这样的,那里有没有办法发送不同进程之间一般Python对象,而无需运行问题成为知道对方何时未发送对象或关闭的问题。另外尝试使用multiprocessing.Queue通常意味着该流程需要由当前流程启动,而当两个流程需要协作时情况并非总是如此。

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

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

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

披露:我是picklepipe的作者。我很想听听你的意见。 :)