web-dev-qa-db-ja.com

Pythonのプロセス間通信

2つの異なるpythonプロセス間でプロセス間通信を行うためのクリーンでエレガントな方法は何ですか?現在OSで名前付きパイプを使用していますが、少しハックを感じます。dbusサービスで自分のものを書き直しました。これは機能しましたが、SSHセッションを介してリモートでコードを実行すると、X11を初期化しようとしますが、これは私がやりたいことにはまったく不要なようです(GUI関連ではありません)。したがって、dbusは少し重すぎるかもしれません。私はソケットを使用して再設計しようとしていましたが、かなり低レベルのようですので、インポートして使用できる高レベルのモジュールがあるかもしれないと思ったので、名前がわからないだけで、= SO最初に..

私の要件は、python foo.pyを実行し、そのプロセスをデーモンのように実行するだけで、python foo.py --barでメッセージを送信できるようにすることです。後者の呼び出しは、既存のプロセスにメッセージを送信して終了する必要があります。成功の場合はリターンコード0で、失敗の場合はその他のコード(双方向通信が必要です)で終了します。

46
wim

multiprocessing library は、ソケットをラップし、任意の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()
85
vsekhar

いや、 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')
36
zeekay

私の経験から言えば、 rpyc は、最もシンプルでエレガントな方法です。

(これは古い質問ですが、つまずいたところです。)

7
shx2

ソケットを使用します。ローカル通信は強力に最適化されているため、パフォーマンスの問題は発生せず、必要に応じてアプリケーションを異なる物理ノードに配布できます。

「低レベル」アプローチに関しては、あなたは正しい。ただし、必要に応じて、より高いレベルのラッパーをいつでも使用できます。 [〜#〜] xmlrpc [〜#〜] は良い候補かもしれませんが、実行しようとしているタスクには多すぎるかもしれません。

Twisted は、 LineReceiver (単純な行ベースのメッセージ用)またはよりエレガントなAMP(ちなみに 標準化された)異なる言語で実装されています )。

3
GaretJax

ソケットを使用しますが、Twistedを使用して抽象化を行い、物事を簡単にします。 それらのシンプルなエコークライアント/サーバーの例 は、開始するのに適した場所です。

ファイルを結合し、渡された引数に応じてクライアントまたはサーバーをインスタンス化して実行するだけです。

1
jozzas

RabbitMQと呼ばれるクロスプラットフォームライブラリ/サーバーをご覧ください。 2プロセス通信には重すぎるかもしれませんが、マルチプロセス通信またはマルチコードベース通信(さまざまな手段(1対多、キューなど)が必要)が必要な場合は、適切なオプションです。

要件:

$ 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
Mika Vatanen