Python中的进程间通信

wim*_*wim 51 python sockets ipc pipe

在两个不同的python进程之间进行进程间通信的干净而优雅的方法是什么?我目前在操作系统中使用命名管道,但感觉有点hacky.我用dbus服务重写了我的东西,但是看起来当通过SSH会话远程运行代码时,它现在尝试初始化X11,这对于我想要做的事情来说似乎完全没有必要(它们与GUI无关).所以也许dbus有点太重量了.我正准备再次使用套接字重新设计,但它看起来很低级,所以我认为可能有一个更高级别的模块我可以导入和使用,我根本就不知道它的名字,我想我应该问SO第一..

我的要求是能够运行python foo.py并让这个过程就像守护进程那样做,并能够发送消息给它python foo.py --bar.后一个调用应该只是向现有进程发送一个消息并终止,可能带有0成功的返回代码或其他失败的代码(因此需要进行一些双向通信).

vse*_*har 93

multiprocessing提供了包装套接字的侦听器和客户端,允许您传递任意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()
Run Code Online (Sandbox Code Playgroud)

您的客户端可以发送命令作为对象:

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()
Run Code Online (Sandbox Code Playgroud)

  • 在python 3中,authkey应该是一个字节字符串:authkey = b'secret password' (11认同)
  • 对于我应该使用哪个端口号有任何规则吗?我应该如何检测端口是否已被使用? (5认同)
  • 真的是一个很好的解决方案,不需要安装额外的库,并且可以按预期工作。谢谢! (4认同)

zee*_*kay 38

不,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')
Run Code Online (Sandbox Code Playgroud)

  • 盯着前 2 个答案后,我不得不问一个问题,是否每个解决方案都需要使用任意端口号?如果该端口已被用于其他用途,这是否会随机搞砸恰好在同一台计算机上运行的不相关的东西? (3认同)

Bas*_*asj 15

根据@vsekhar 的回答,这是一个 Python 3 版本,其中包含更多详细信息和多个连接:

服务器

from multiprocessing.connection import Listener

listener = Listener(('localhost', 6000), authkey=b'secret password')
running = True
while running:
    conn = listener.accept()
    print('connection accepted from', listener.last_accepted)
    while True:
        msg = conn.recv()
        print(msg)
        if msg == 'close connection':
            conn.close()
            break
        if msg == 'close server':
            conn.close()
            running = False
            break
listener.close()
Run Code Online (Sandbox Code Playgroud)

客户

from multiprocessing.connection import Client
import time

# Client 1
conn = Client(('localhost', 6000), authkey=b'secret password')
conn.send('foo')
time.sleep(1)
conn.send('close connection')
conn.close()

time.sleep(1)

# Client 2
conn = Client(('localhost', 6000), authkey=b'secret password')
conn.send('bar')
conn.send('close server')
conn.close()
Run Code Online (Sandbox Code Playgroud)


shx*_*hx2 8

根据我的经验,这rpyc是迄今为止最简单,最优雅的方式.

(我知道这是一个老问题,但我偶然发现它......)

  • @shx2,您至少可以在答案中提供一段代码来展示它的外观。对于任何寻找快速入门示例的人,请参阅[这篇文章](/sf/answers/1885415941/)。 (7认同)
  • 这是天才。感谢您向我介绍这个图书馆。我现在需要的是第二个投票按钮。 (2认同)

Gar*_*Jax 6

我会使用套接字;本地通信经过了高度优化,因此您不应该遇到性能问题,并且可以在需要时将应用程序分发到不同的物理节点。

关于“低级”方法,您是对的。但是您始终可以根据需要使用更高级别的包装器。XMLRPC可能是一个不错的候选者,但对于您要执行的任务来说,它可能有点过头了。

Twisted提供了一些很好的协议简单实现,例如LineReceiver(用于简单的基于行的消息)或更优雅的 AMP(顺便说一下,它被标准化并以不同的语言实现)。