Межпроцессное взаимодействие в Python - PullRequest
45 голосов
/ 03 августа 2011

Что такое чистый и элегантный способ межпроцессного взаимодействия между двумя разными процессами Python? В настоящее время я использую именованные каналы в ОС, но это выглядит немного странно. Я переписал свои вещи с помощью dbus сервисов, которые работали, но кажется, что при удаленном запуске кода через сеанс SSH он теперь пытается инициализировать X11, что кажется совершенно ненужным для того, что я хочу сделать (они не связаны с GUI) , Так что, возможно, dbus слишком тяжеловес. Я собирался снова сделать редизайн с использованием сокетов, но он кажется довольно низкоуровневым, поэтому я подумал, что мог бы быть модуль более высокого уровня, который я мог бы импортировать и использовать, которого я просто не знаю, и я подумал, что мне следует спросить о SO первый ..

Мое требование - иметь возможность запускать python foo.py и иметь этот процесс, просто выполняющий свои задачи, как демон, и иметь возможность отправлять ему сообщения с помощью python foo.py --bar. Последний вызов должен просто отправить сообщение существующему процессу и завершиться, возможно, с кодом возврата 0 для успеха или другим для отказа (поэтому потребуется некоторая двусторонняя связь).

Ответы [ 6 ]

84 голосов
/ 03 августа 2011

Библиотека 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()
36 голосов
/ 03 августа 2011

Нет, 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 голосов
/ 04 марта 2013

Исходя из моего опыта, rpyc - безусловно, самый простой и элегантный способ сделать это.

(я знаю, что это старый вопрос, но я простонаткнулся на это ..)

3 голосов
/ 03 августа 2011

Я бы использовал сокеты;локальная связь была сильно оптимизирована, поэтому у вас не должно быть проблем с производительностью, и это дает вам возможность распределить ваше приложение по разным физическим узлам, если возникнут потребности.

Что касается подхода «низкого уровня», ты прав.Но вы всегда можете использовать обертку более высокого уровня в зависимости от ваших потребностей. XMLRPC может быть хорошим кандидатом, но это может быть излишним для задачи, которую вы пытаетесь выполнить.

Twisted предлагает несколько хороших протоколов простых реализаций, таких как LineReceiver (для простых линейных сообщений) или более элегантный AMP (который, кстати, стандартизирован и реализован на разных языках ).

1 голос
/ 17 октября 2016

Проверьте кроссплатформенную библиотеку / сервер под названием 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

1 голос
/ 03 августа 2011

Я бы использовал сокеты, но использовал Twisted, чтобы дать вам некоторую абстракцию и сделать вещи проще. Их пример простого эхо-клиента / сервера - хорошее начало).

...