Межпроцессная связь в Python
что такое чистый и элегантный способ сделать межпроцессную связь между двумя различными процессами python? В настоящее время я использовать именованные каналы в ОС, но он чувствует себя немного богатство. Я переписал свои вещи с dbus
службы, которые работали, но, похоже, при удаленном запуске кода через сеанс SSH он теперь пытается инициализировать X11, который кажется совершенно ненужным для вещей, которые я хочу сделать (они не связаны с GUI). Так что, может быть dbus
немного тяжеловес. Я собирался перепроектировать снова используя сокеты, но это кажется довольно низкоуровневым, поэтому я подумал, что может быть модуль более высокого уровня, который я мог бы импортировать и использовать, который я просто не знаю имени, и я подумал, что должен сначала спросить об этом..
мое требование состоит в том, чтобы иметь возможность запускать python foo.py
и этот процесс просто делает это там, как демон, и может отправлять сообщения ему с python foo.py --bar
. Последний вызов должен просто отправить сообщение существующему процессу и завершиться, возможно, с кодом возврата 0
для успеха или другого для отказа (поэтому потребуется некоторая двусторонняя связь).
6 ответов
на multiprocessing
библиотека предоставляет слушатели и клиенты Это обертывание сокетов и позволяет передавать произвольные объекты 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 (для простых сообщений на основе строк) или более элегантный усилитель (который, кстати, стандартизировано и реализовано на разных языках).
Я бы использовал сокеты, но используйте Twisted, чтобы дать вам некоторую абстракцию и сделать вещи легкими. их простой Эхо-клиент / сервер пример - это хорошее место для начала.
вам просто нужно будет объединить файлы и создать экземпляр и запустить либо клиент, либо сервер в зависимости от переданных аргументов.
Проверьте кросс-платформенную библиотеку / сервер под названием 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