2011-08-03 35 views
28

什么是在两个不同的python进程之间进行进程间通信的干净优雅的方式?我目前在操作系统中使用命名管道,但感觉有点不好意思。我用dbus服务重写了我的东西,这很有效,但似乎在通过SSH会话远程运行代码时,它现在尝试初始化X11,这对于我想要执行的操作(它们不是GUI相关的)似乎完全没有必要。所以也许dbus有点太重量级了。我正要重新使用套接字重新设计,但它看起来很低级,所以我认为可能有一个更高级别的模块,我可以导入和使用,我根本不知道名称,我想我应该询问SO第一..python中的进程间通信

我的要求是能够运行python foo.py,并有那个过程,就像一个守护进程,并能够发送消息与它python foo.py --bar。后者的调用应该只是向现有进程发送一条消息并终止,可能返回代码0用于成功或其他失败(因此需要进行一些双向通信)。

回答

25

那么,zeromq是要走的路。美味,不是吗?

import argparse 
import zmq 

parser = argparse.ArgumentParser(description='zeromq server/client') 
parser.add_argument('--bar') 
args = parser.parse_args() 

if args.bar: 
    # client 
    context = zmq.Context() 
    socket = context.socket(zmq.REQ) 
    socket.connect('tcp://127.0.0.1:5555') 
    socket.send(args.bar) 
    msg = socket.recv() 
    print msg 
else: 
    # server 
    context = zmq.Context() 
    socket = context.socket(zmq.REP) 
    socket.bind('tcp://127.0.0.1:5555') 
    while True: 
     msg = socket.recv() 
     if msg == 'zeromq': 
      socket.send('ah ha!') 
     else: 
      socket.send('...nah') 
+0

感谢,非常好 – wim

+1

可以修改这个工作在多线程环境吗?我现在有几个工作线程连接,并且它似乎导致zmq c代码断言失败 – wim

+0

您也可以用pizco打包zmq: https://pizco.readthedocs.io/en/latest/ –

3

我会使用套接字;本地通信得到了极大的优化,所以您不应该遇到性能问题,并且如果出现需求,它可以让您将应用程序分发到不同的物理节点。

关于“低级”方法,你是对的。但您可以根据需要随时使用更高级别的包装。 XMLRPC可能是一个很好的候选人,但对于您要执行的任务而言,这可能是过度的。

Twisted提供了一些很好的协议简单实现,例如LineReceiver(用于简单的基于行的消息)或更优雅的AMP(顺便提一句,它是standardized and implemented in different languages)。

+0

import pika, bson connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost')) channel = connection.channel() channel.exchange_declare(exchange='logs', type='fanout') result = channel.queue_declare(exclusive=True) queue_name = result.method.queue channel.queue_bind(exchange='logs', queue=queue_name) def callback(ch, method, properties, body): data = bson.loads(body) print("Received", data) channel.basic_consume(callback, queue=queue_name, no_ack=True) channel.start_consuming() 

实例不是在Windows上本地使用的插入相对较慢? (或者我是否想到所有本地IPC?)所以它可能取决于OP的部署环境。如果你使用的是Twisted,他们也有'ProcessProtocol',这可能是值得关注的。 – detly

+0

ProcessProtocol解决了完全不同的问题,不能用于与已经运行的进程进行通信。 – GaretJax

+0

关于窗户,你可能是对的;我在Windows上只有非常有限的经验。关于“所有本地IPC”,如果我能找到我上面提到的参考资料,我会添加链接。 – GaretJax

1

我会使用套接字,但使用Twisted给你一些抽象,并使事情变得容易。 Their Simple Echo Client/Server example是一个很好的开始。

根据传递的参数,您只需组合文件并实例化并运行客户端或服务器即可。

61

multiprocessing library提供listeners and clients那套插座,并允许您通过任意的Python对象。

您的服务器可以听得到的Python对象:

from multiprocessing.connection import Listener 

address = ('localhost', 6000)  # family is deduced to be 'AF_INET' 
listener = Listener(address, authkey='secret password') 
conn = listener.accept() 
print 'connection accepted from', listener.last_accepted 
while True: 
    msg = conn.recv() 
    # do something with msg 
    if msg == 'close': 
     conn.close() 
     break 
listener.close() 

您的客户端可以发送命令的对象:

from multiprocessing.connection import Client 

address = ('localhost', 6000) 
conn = Client(address, authkey='secret password') 
conn.send('close') 
# can also send arbitrary objects: 
# conn.send(['a', 2.5, None, int, sum]) 
conn.close() 
+0

数组对象没有在代码中使用,我认为你应该删除导入。 –

+0

删除导入 – vsekhar

+1

在python 3中,authkey应该是一个字节字符串:authkey = b'secret密码' –

7

从我的经验,rpyc是迄今为止最简单,最优雅的方式去做吧。

(我知道这是一个老问题,但我只是偶然发现了它。)

1

退房一个跨平台的库/服务器调用的RabbitMQ。对于双进程通信来说可能过于沉重,但如果您需要多进程或多代码库通信(使用各种不同的方式,例如一对多,队列等),这是一个不错的选择。

要求:

$ pip install pika 
$ pip install bson # for sending binary content 
$ sudo apt-get rabbitmq-server # ubuntu, see rabbitmq installation instructions for other platforms 

出版商(发送数据):

import pika, time, bson, os 

connection = pika.BlockingConnection(pika.ConnectionParameters('localhost')) 
channel = connection.channel() 
channel.exchange_declare(exchange='logs', type='fanout') 

i = 0 
while True: 
    data = {'msg': 'Hello %s' % i, b'data': os.urandom(2), 'some': bytes(bytearray(b'\x00\x0F\x98\x24'))} 
    channel.basic_publish(exchange='logs', routing_key='', body=bson.dumps(data)) 
    print("Sent", data) 
    i = i + 1 
    time.sleep(1) 

connection.close() 

订户(接收数据,可以是多个):基于https://www.rabbitmq.com/tutorials/tutorial-two-python.html