在两个不同的python进程之间进行进程间通信的干净而优雅的方法是什么?我目前在操作系统中使用命名管道,但感觉有点hacky。我用dbus
服务改写了我的东西,虽然有效,但似乎在通过SSH会话远程运行代码时,它现在尝试初始化X11,这似乎对我想要做的事情完全没有必要(它们与GUI无关)。所以也许dbus
有点太重量了。我正准备再次使用套接字进行重新设计,但它看起来很低级,所以我想可能有一个更高级别的模块我可以导入和使用,我根本就不知道它的名字,我想我应该问SO第一..
我的要求是能够运行python foo.py
并让这个过程就像守护进程一样,并且能够使用python foo.py --bar
向它发送消息。后一个调用应该只向现有进程发送一条消息并终止,可能返回代码为0
表示成功或其他失败(因此需要进行一些双向通信)。
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()
不,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')
根据我的经验,rpyc
是迄今为止最简单,最优雅的方式。
(我知道这是一个老问题,但我偶然发现它......)
我会用套接字;本地通信得到了极大的优化,因此您不应该遇到性能问题,并且如果需要,您可以将应用程序分发到不同的物理节点。
关于“低级”方法,你是对的。但您可以根据需要始终使用更高级别的包装器。 XMLRPC可能是一个很好的候选人,但对你正在尝试执行的任务来说可能有些过分。
Twisted提供了一些很好的协议简单实现,例如LineReceiver(用于简单的基于行的消息)或更优雅的AMP(顺便说一下,standardized and implemented in different languages)。
我会使用套接字,但使用Twisted为您提供一些抽象,并使事情变得简单。 Their Simple Echo Client / Server example是一个很好的起点。
您只需要组合文件并实例化并运行客户端或服务器,具体取决于传递的参数。
查看一个名为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的示例