2つの異なるpythonプロセス間でプロセス間通信を行うためのクリーンでエレガントな方法は何ですか?現在OSで名前付きパイプを使用していますが、少しハックを感じます。dbus
サービスで自分のものを書き直しました。これは機能しましたが、SSHセッションを介してリモートでコードを実行すると、X11を初期化しようとしますが、これは私がやりたいことにはまったく不要なようです(GUI関連ではありません)。したがって、dbus
は少し重すぎるかもしれません。私はソケットを使用して再設計しようとしていましたが、かなり低レベルのようですので、インポートして使用できる高レベルのモジュールがあるかもしれないと思ったので、名前がわからないだけで、= SO最初に..
私の要件は、python foo.py
を実行し、そのプロセスをデーモンのように実行するだけで、python foo.py --bar
でメッセージを送信できるようにすることです。後者の呼び出しは、既存のプロセスにメッセージを送信して終了する必要があります。成功の場合はリターンコード0
で、失敗の場合はその他のコード(双方向通信が必要です)で終了します。
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()
いや、 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 (単純な行ベースのメッセージ用)またはよりエレガントなAMP(ちなみに 標準化された)異なる言語で実装されています )。
ソケットを使用しますが、Twistedを使用して抽象化を行い、物事を簡単にします。 それらのシンプルなエコークライアント/サーバーの例 は、開始するのに適した場所です。
ファイルを結合し、渡された引数に応じてクライアントまたはサーバーをインスタンス化して実行するだけです。
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 に基づく例