使用Python的RPyC库进行远程调用

目录

作者:杨冬 欢迎转载,也请保留这段声明。谢谢!
出处:https://andyyoung01.github.io/http://andyyoung01.16mb.com/

RPyC(Remote Python Call)是用于远程过程调用,集群和分布式计算的python库。RPyC克服了进程和计算机之间的物理界限,使得操作远程对象就像操作本地对象一样。

使用rpyc编写c/s结构程序,完全不用考虑老式的socket编程,现在只用编写简单的3、5行代码即可完成以前多行代码完成的功能。在RPyC 3.0版之后,其提供了一种基于服务的新的RPyC编程模型。基本上,一个服务有如下的模板代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import rpyc
class MyService(rpyc.Service):
def on_connect(self):
# code that runs when a connection is created
# (to init the serivce, if needed)
pass
def on_disconnect(self):
# code that runs when the connection has already closed
# (to finalize the service, if needed)
pass
def exposed_get_answer(self): # this is an exposed method
return 42
def get_question(self): # while this method is not exposed
return "what is the airspeed velocity of an unladen swallow?"
if __name__ == "__main__":
from rpyc.utils.server import ThreadedServer
t = ThreadedServer(MyService, port = 18861)
t.start()

上面的代码有几点需要注意:

  • 自定义的服务类需继承自rpyc.Service类,类的名称应该以Service结尾,这种命名方式便于对服务进行注册。上面的代码将MyService类注册了一个名称为“my“的服务。
  • 可以自定义服务的初始化/结束代码,如上面的on_connecton_disconnect方法。
  • 方法名以exposed_开始的方法可以被远程访问到,其它的方法不能被远程访问。例如上面例子的exposed_get_answer方法,客户端可以通过名称get_answer远程调用,但是客户端调用不了 get_question方法。

在客户端,服务被暴露为连接的root对象,下面看一下客户端的调用实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>>> import rpyc
>>> c = rpyc.connect("localhost", 18861)
>>> c.root #这是“root对象”
<__main__.MyService object at 0x7ff294269948>
>>> c.root.get_answer
<bound method MyService.exposed_get_answer of <__main__.MyService object at 0x7ff294269948>>
>>> c.root.get_answer()
42
>>> c.root.exposed_get_answer() #也可以加上“exposed_”前缀进行调用
42
>>> c.root.get_question()
Traceback (most recent call last):
...
_get_exception_class.<locals>.Derived: 'MyService' object has no attribute 'exposed_get_question'
========= Remote Traceback (1) =========
Traceback (most recent call last):
File "/home/yangdong/python_env/py352/lib/python3.5/site-packages/rpyc/core/protocol.py", line 305, in _dispatch_request
res = self._HANDLERS[handler](self, *args)
...
AttributeError: 'MyService' object has no attribute 'exposed_get_question'

通过上面的实例可见通过RPyC编写远程过程调用是多么得简单。

RPyC不仅仅对Socket进行了封装,它还支持同步与异步操作、回调和远程服务以及透明的对象代理,可以在Server与Client之间传递Python的任意对象,性能也比较高效。可以参考官方文档的教程进行更多了解。