2011-08-03 34 views
28

什麼是在兩個不同的python進程之間進行進程間通信的乾淨優雅的方式?我目前在操作系統中使用命名管道,但感覺有點不好意思。我用dbus服務重寫了我的東西,這很有效,但似乎在通過SSH會話遠程運行代碼時,它現在嘗試初始化X11,這對於我想要執行的操作(它們不是GUI相關的)似乎完全沒有必要。所以也許dbus有點太重量級了。我正要重新使用套接字重新設計,但它看起來很低級,所以我認爲可能有一個更高級別的模塊,我可以導入和使用,我根本不知道名稱,我想我應該詢問SO第一..python中的進程間通信

我的要求是能夠運行python foo.py,並有那個過程,就像一個守護進程,並能夠發送消息與它python foo.py --bar。後者的調用應該只是向現有進程發送一條消息並終止,可能返回代碼0用於成功或其他失敗(因此需要進行一些雙向通信)。

回答

25

那麼,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') 
+0

感謝,非常好 – wim

+1

可以修改這個工作在多線程環境嗎?我現在有幾個工作線程連接,並且它似乎導致zmq c代碼斷言失敗 – wim

+0

您也可以用pizco打包zmq: https://pizco.readthedocs.io/en/latest/ –

3

我會使用套接字;本地通信得到了極大的優化,所以您不應該遇到性能問題,並且如果出現需求,它可以讓您將應用程序分發到不同的物理節點。

關於「低級」方法,你是對的。但您可以根據需要隨時使用更高級別的包裝。 XMLRPC可能是一個很好的候選人,但對於您要執行的任務而言,這可能是過度的。

Twisted提供了一些很好的協議簡單實現,例如LineReceiver(用於簡單的基於行的消息)或更優雅的AMP(順便提一句,它是standardized and implemented in different languages)。

+0

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

實例不是在Windows上本地使用的插入相對較慢? (或者我是否想到所有本地IPC?)所以它可能取決於OP的部署環境。如果你使用的是Twisted,他們也有'ProcessProtocol',這可能是值得關注的。 – detly

+0

ProcessProtocol解決了完全不同的問題,不能用於與已經運行的進程進行通信。 – GaretJax

+0

關於窗戶,你可能是對的;我在Windows上只有非常有限的經驗。關於「所有本地IPC」,如果我能找到我上面提到的參考資料,我會添加鏈接。 – GaretJax

1

我會使用套接字,但使用Twisted給你一些抽象,並使事情變得容易。 Their Simple Echo Client/Server example是一個很好的開始。

根據傳遞的參數,您只需組合文件並實例化並運行客戶端或服務器即可。

61

multiprocessing library提供listeners and clients那套插座,並允許您通過任意的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() 
+0

數組對象沒有在代碼中使用,我認爲你應該刪除導入。 –

+0

刪除導入 – vsekhar

+1

在python 3中,authkey應該是一個字節字符串:authkey = b'secret密碼' –

7

從我的經驗,rpyc是迄今爲止最簡單,最優雅的方式去做吧。

(我知道這是一個老問題,但我只是偶然發現了它。)

1

退房一個跨平臺的庫/服務器調用的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() 

訂戶(接收數據,可以是多個):基於https://www.rabbitmq.com/tutorials/tutorial-two-python.html