Межпроцессное взаимодействие в Python
Что такое чистый и элегантный способ межпроцессного взаимодействия между двумя различными процессами python? В настоящее время я использую именованные каналы в ОС, но он немного взломан. Я переписал свой материал с dbus
службами, которые работали, но, похоже, при запуске кода удаленно через сеанс SSH он теперь пытается инициализировать X11, который кажется совершенно ненужным для вещей, которые я хочу сделать (они не связаны с графическим интерфейсом), Так что, может быть, dbus
слишком тяжело. Я собирался снова перепроектировать, используя сокеты, но он выглядит довольно низкоуровневым, поэтому я подумал, что может быть модуль более высокого уровня, который я мог бы импортировать и использовать, который я просто не знаю имени, и я подумал, что я должен спросить о SO первый..
Мое требование состоит в том, чтобы иметь возможность запускать python foo.py
и иметь этот процесс, просто делающий это, как демон, и иметь возможность отправлять ему сообщения с помощью python foo.py --bar
. Последний вызов должен просто отправить сообщение в существующий процесс и завершиться, возможно, с кодом возврата 0
для успеха или другого для отказа (так что потребуется некоторая двусторонняя связь).
Ответы
Ответ 1
Библиотека 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()
Ответ 2
Nah, 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')
Ответ 3
По моему опыту rpyc
- это самый простой и изящный способ сделать это.
(Я знаю, что это старый вопрос, но я только что наткнулся на него.)
Ответ 4
Я бы использовал сокеты; локальная связь была сильно оптимизирована, поэтому у вас не должно быть проблем с производительностью, и это дает вам возможность распространять ваше приложение на разные физические узлы, если это необходимо.
Что касается "низкоуровневого" подхода, вы правы. Но вы всегда можете использовать обертку более высокого уровня в зависимости от ваших потребностей. XMLRPC может быть хорошим кандидатом, но, возможно, это слишком сложно для задачи, которую вы пытаетесь выполнить.
Twisted предлагает некоторые хорошие простые простые протоколы, такие как LineReceiver (для простых текстовых сообщений) или более элегантный AMP (который, кстати, был стандартизован и реализован на разных языках).
Ответ 5
Я бы использовал сокеты, но использовал Twisted, чтобы дать вам некоторую абстракцию и сделать все просто. Их простой пример Echo Client/Server - это хорошее место для начала.
Вам просто нужно объединить файлы и создать экземпляр и запустить клиент или сервер в зависимости от переданных аргументов.
Ответ 6
Проверьте кросс-платформенную библиотеку/сервер под названием 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