很久之前的文章中提到过用RPyC进行进程间通信,

# 启动server,在rpyc/bin目录下
python rpyc_classic.py

# 客户端进行连接
import rpyc
conn = rpyc.classic.connect("localhost")

# 通过conn.modules访问server进程内的module
print conn.modules.sys

在Classic连接模式下,客户端代码可以访问到服务端的模块。这种连接方式暴露的内容过多,因此RPyC还有一种Service形式提供连接的方式。但Classic模式适用于什么场景呢?最近找到一个比较合适的情况,就是将其用于在多进程环境下进行调试连接,查看进程中的数据。

不过上面例子中的访问方式并没有那么方便,访问模块都需要从conn.modules中获取,有没有可能像导入本地模块一样导入远程模块?在阅读了Python PEP0302后,发现可以通过定制import流程来达到此功能。

以一个简单的例子来说明一下,定义RPyC Server端代码,

// foobar.py
from rpyc.core import SlaveService
from rpyc.utils.server import ThreadedServer
import threading

class Foobar(object):
    pass

class RPyCThread(threading.Thread):

    def run(self):
        try:
            server = ThreadedServer(SlaveService, port=18812, reuse_addr=True)
            server.start()
        except Exception as e:
            print e

thread = RPyCThread()
thread.start()

在RPyC客户端代码中定制module加载过程,

class RpycLoader(object):
    
    def __init__(self, host, port):
        self.conn = None
        self.port = port
        self.host = host

    def find_module(self, fullname, path=None):
        return self

    def load_module(self, full_name):
        if self.conn is None:
            self.conn = rpyc.classic.connect(self.host, self.port)
        module = getattr(self.conn.modules, full_name, None)
        return module

def connect(host, port):
    sys.meta_path = [RpycLoader(host, port)]

在命令行中进入Python环境,首先连接RPyC,而后就能够将远程模块像本地模块那样导入,

import sys
connect('locast', 18812)
from foobar import Foobar