2011-08-03 23 views
28

Cách sạch sẽ và thanh lịch để thực hiện liên lạc giữa hai quá trình python khác nhau là gì? Tôi hiện đang sử dụng đường ống được đặt tên trong hệ điều hành, nhưng nó cảm thấy một chút hacky. Tôi đã viết lại các công cụ của mình với các dịch vụ dbus, hoạt động, nhưng có vẻ như khi chạy mã từ xa thông qua một phiên SSH nó đang cố gắng khởi tạo X11 mà dường như hoàn toàn không cần thiết cho những thứ tôi muốn làm (chúng không liên quan đến GUI). Vì vậy, có lẽ dbus là một chút quá nặng. Tôi sắp thiết kế lại bằng cách sử dụng ổ cắm, nhưng có vẻ khá thấp nên tôi nghĩ có thể có một mô-đun mức cao hơn tôi có thể nhập và sử dụng mà tôi không biết tên, và tôi nghĩ tôi nên hỏi về SO đầu tiên ..liên lạc giữa các quy trình trong python

Yêu cầu của tôi là có thể chạy python foo.py và có quy trình đó chỉ cần thực hiện điều đó ở đó, như một daemon và có thể gửi tin nhắn tới số python foo.py --bar. Cuộc gọi thứ hai sẽ chỉ gửi một thông điệp đến quá trình hiện có và chấm dứt, có thể với mã trả về 0 để thành công hay khác cho thất bại (do đó, một số giao tiếp hai chiều sẽ được yêu cầu).

Trả lời

25

Không, zeromq là cách để thực hiện. Ngon, phải không?

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

cảm ơn, rất đẹp – wim

+1

điều này có thể được sửa đổi để hoạt động trong môi trường đa luồng không? tôi có một số chủ đề công nhân kết nối ngay bây giờ, và nó dường như gây ra lỗi xác nhận trong mã zmq – wim

+0

Bạn cũng có thể bọc zmq với pizco: https://pizco.readthedocs.io/en/latest/ –

3

Tôi sẽ sử dụng ổ cắm; truyền thông địa phương đã được tối ưu hóa mạnh mẽ, vì vậy bạn không nên có vấn đề về hiệu suất và nó cung cấp cho bạn khả năng phân phối ứng dụng của bạn đến các nút vật lý khác nhau nếu nhu cầu phát sinh.

Liên quan đến cách tiếp cận "cấp thấp", bạn nói đúng. Nhưng bạn luôn có thể sử dụng trình bao bọc cấp cao hơn tùy thuộc vào nhu cầu của bạn. XMLRPC có thể là một ứng cử viên tốt, nhưng nó có thể là quá mức cần thiết cho công việc bạn đang cố gắng thực hiện.

Twisted cung cấp một số giao thức đơn giản, ví dụ như LineReceiver (đối với thông điệp dựa trên dòng đơn giản) hoặc AMP thanh lịch hơn (được, bằng cách này, standardized and implemented in different languages).

+0

Không phải là tương đối chậm để sử dụng cục bộ trên Windows? (Hoặc tôi đang nghĩ đến tất cả IPC địa phương?) Vì vậy, nó có thể phụ thuộc vào môi trường triển khai OPs. Và nếu bạn đang sử dụng Twisted, họ cũng có 'ProcessProtocol', điều này có thể đáng xem. – detly

+0

ProcessProtocol giải quyết một vấn đề hoàn toàn khác và không thể sử dụng để giao tiếp với một tiến trình đang chạy. – GaretJax

+0

Về cửa sổ, bạn có thể đúng; Tôi chỉ có một kinh nghiệm rất hạn chế trên cửa sổ. Về "tất cả IPC địa phương", nếu tôi sẽ tìm thấy tài liệu tham khảo của tôi cho những gì đã nêu ở trên, tôi sẽ thêm liên kết. – GaretJax

1

Tôi sẽ sử dụng ổ cắm, nhưng sử dụng Twisted để cung cấp cho bạn một số trừu tượng, và để làm cho mọi thứ dễ dàng. Their Simple Echo Client/Server example là một nơi tốt để bắt đầu.

Bạn chỉ cần kết hợp các tệp và khởi tạo và chạy ứng dụng khách hoặc máy chủ tùy thuộc vào (các) đối số đã truyền.

61

Các multiprocessing library cung cấp listeners and clients bọc ổ cắm và cho phép bạn để vượt qua đối tượng python tùy ý.

Máy chủ của bạn có thể lắng nghe để nhận đối tượng 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() 

Khách hàng của bạn có thể gửi lệnh như các đối tượng:

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

đối tượng mảng không được sử dụng trong mã tôi nghĩ bạn nên xóa phần nhập. –

+0

đã xóa nhập – vsekhar

+1

Trong python 3 authkey phải là chuỗi byte: authkey = b'secret password ' –

7

Từ kinh nghiệm của tôi, rpyc đến nay là cách đơn giản và thanh lịch nhất để đi về nó.

(Tôi biết đây là một câu hỏi cũ, nhưng tôi đã chỉ cần stumbled khi nó ..)

1

Kiểm tra thư viện/máy chủ nền tảng gọi RabbitMQ. Có thể quá nặng đối với giao tiếp hai bước, nhưng nếu bạn cần giao tiếp đa tiến trình hoặc đa mã (với nhiều phương tiện khác nhau, ví dụ: một, nhiều, hàng đợi, vv), đó là một lựa chọn tốt.

Yêu cầu:

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

Nhà xuất bản (gửi dữ liệu):

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

Subscriber (nhận dữ liệu, có thể là nhiều):

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

ví dụ dựa trên https://www.rabbitmq.com/tutorials/tutorial-two-python.html