Komunikacja międzyprocesowa w Pythonie

Jaki jest czysty i elegancki sposób komunikacji międzyprocesowej pomiędzy dwoma różnymi procesami Pythona? Obecnie używam nazwanych rur w systemie operacyjnym, ale wydaje się to trochę trudne. Przepisałem moje rzeczy z dbus usługi, które działały, ale wydaje się, że uruchamiając kod zdalnie przez sesję SSH, teraz próbuje zainicjować X11, co wydaje się całkowicie niepotrzebne dla rzeczy, które chcę robić (nie są związane z GUI). Więc może dbus jest trochę za ciężki. Miałem zamiar ponownie przeprojektować używając gniazd, ale wydaje się to dość niski poziom, więc pomyślałem, że może być moduł wyższego poziomu, który mógłbym zaimportować i użyć, którego po prostu nie znam nazwy, i pomyślałem, że powinienem najpierw zapytać o to..

Moim wymogiem jest to, aby móc uruchomić python foo.py i mieć ten proces po prostu robi to, co tam jest, jak demon, i móc wysyłać do niego wiadomości za pomocą python foo.py --bar. To ostatnie wywołanie powinno po prostu wysłać wiadomość do istniejącego procesu i zakończyć się, ewentualnie z kodem zwrotnym 0 dla powodzenia lub Inne za awarię (więc wymagana będzie dwukierunkowa komunikacja).

Author: jww, 2011-08-03

6 answers

The multiprocessing biblioteka dostarcza słuchaczy i klientów , które zawijają gniazda i umożliwiają przekazywanie dowolnych obiektów Pythona.

Twój serwer może nasłuchiwać odbierania obiektów Pythona:

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()

Twój Klient może wysyłać polecenia jako obiekty:

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()
 70
Author: vsekhar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-14 00:36:51

Nie, zeromq jest drogą do zrobienia. Pyszne, prawda?

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')
 34
Author: zeekay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-03 03:39:45

Z mojego doświadczenia, rpyc jest zdecydowanie najprostszym i najbardziej eleganckim sposobem, aby to zrobić.

(wiem, że to stare pytanie, ale właśnie się na nie natknąłem..)

 7
Author: shx2,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-08 04:58:51

Użyłbym socketów; lokalna komunikacja była mocno zoptymalizowana, więc nie powinieneś mieć problemów z wydajnością i daje Ci możliwość dystrybucji aplikacji do różnych fizycznych węzłów, jeśli zajdzie taka potrzeba.

Jeśli chodzi o podejście "niskiego poziomu", masz rację. Ale zawsze możesz użyć owijarki wyższego poziomu w zależności od potrzeb. XMLRPC może być dobrym kandydatem, ale to może przesada dla zadania, które próbujesz wykonaj.

Twisted oferuje kilka dobrych implementacji protokołu, takich jak LineReceiver (dla prostych wiadomości liniowych) lub bardziej elegancki AMP (który został, nawiasem mówiąc, ustandaryzowany i zaimplementowany w różnych językach ).

 3
Author: GaretJax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-03 02:01:08

Użyłbym gniazd, ale użyłbym Twisted, aby dać ci trochę abstrakcji i ułatwić sprawy. ich prosty przykład klienta / serwera Echo jest dobrym miejscem do rozpoczęcia.

Trzeba by po prostu połączyć pliki i utworzyć instancję i uruchomić klienta lub serwer w zależności od przekazanych argumentów.

 1
Author: jozzas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-03 03:24:43

Sprawdź wieloplatformową bibliotekę / serwer o nazwie RabbitMQ. Może to być zbyt ciężkie dla komunikacji dwu procesowej, ale jeśli potrzebujesz komunikacji wieloprocesowej lub wielo-kodowej (z różnymi środkami, np. jeden do wielu, kolejki, itp.), Jest to dobra opcja.

Wymagania:

$ pip install pika
$ pip install bson # for sending binary content
$ sudo apt-get rabbitmq-server # ubuntu, see rabbitmq installation instructions for other platforms

Wydawca (wysyła dane):

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()

Abonent (odbiera dane, może być wiele):

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()

Przykłady oparte na https://www.rabbitmq.com/tutorials/tutorial-two-python.html

 1
Author: Mika Vatanen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-17 18:40:02