Межпроцессная связь в 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