Python中的进程间通信

问题描述 投票:44回答:6

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

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

python sockets pipe ipc
6个回答
84
投票

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

36
投票

不,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')

7
投票

根据我的经验,rpyc是迄今为止最简单,最优雅的方式。

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


3
投票

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

关于“低级”方法,你是对的。但您可以根据需要始终使用更高级别的包装器。 XMLRPC可能是一个很好的候选人,但对你正在尝试执行的任务来说可能有些过分。

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


1
投票

我会使用套接字,但使用Twisted为您提供一些抽象,并使事情变得简单。 Their Simple Echo Client / Server example是一个很好的起点。

您只需要组合文件并实例化并运行客户端或服务器,具体取决于传递的参数。


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

订阅者(接收数据,可以是多个):

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

基于https://www.rabbitmq.com/tutorials/tutorial-two-python.html的示例

© www.soinside.com 2019 - 2024. All rights reserved.