基于python实现rpc远程过程调用

目录
  • 基于python实现RPC的demo
  • 前言
  • 一、主要内容
  • 二、实现步骤
    • 1. 进程间的通信
    • 2. 异步回调实现思路
  • 总结

基于python实现RPC的demo

这是一个远程过程调用(RPC)的实现demo,可以实现不同的python进程之间通信和互相调用函数,简单易用,易于扩展。更多功能也可进一步完善,本文介绍了该实现的主要思路。

前言

计划手撸一个rpc甚久了,在间歇性push自己下终于完成的差不多了。写这个demo的原因,1)是为了学习与思考下这部分主体功能和实现思路,2)是调包时可以毫无心理负担,并产生一种不过如此的优越感。
实现这部分内容主要依据的还是自己的想法,因此可能会有bug或者有更好的实现方式,仅供学习和参考,完整代码可参考Gitee链接。
实现的时候用的是python2.7,忘记换了,下次一定更新。

一、主要内容

所谓RPC,是远程过程调用(Remote Procedure Call)的简写,网上解释很多,简单来说,就是在当前进程调用其他进程的函数时,体验就像是调用本地写的函数一般。
本文实现的是在本地调用远端的类class对象的接口,也就是本地的client不实例化类对象,调用的是server端的类对象接口。
为了达到让调用层无须关心底层实现,拥有丝滑般的体验,就需要以下几个部分:

  • 客户端需要把类的接口提取出来,并将调用函数事件捕获存储起来;服务端需要把类的公有函数作为可远程调用的接口。
  • 客户端把调用函数的事件(调用的函数,参数)进行序列化并发送给服务端;服务端将客户端的调用事件反序列化,并执行相应的接口,将返回值发送给客户端。
  • 客户端与服务端通过某种方式(一般就是网络socket)进行通信。

在下面时序图的灰色部分,对于调用方来说是透明的,它的执行结果应该和执行本地的函数时一致的。

二、实现步骤

1. 进程间的通信

本文采用了基于TCP的sokcet连接来进行进程之间的通信,更多实现细节可参考之前博客。
在此需要注意:

本文采用了select模块来监听网络事件,如果服务端未收到任何的网络消息会一直阻塞在这儿。如果服务端除了提供rpc调用服务之外还需要执行其他逻辑,那么应当采用非阻塞,轮询socket的方式来判断是否有新的网络事件。

# ServerBase.py
def process(self):
    readable, writable, exceptional = select.select(self.inputs, self.outputs, self.conns.values())
    for conn in readable:
        if conn is self.socket:
            self._handle_conn()
        else:
            self._handle_recv(conn)
    for conn in writable:
        pass
    for conn in exceptional:
        self._handle_leave(conn)

客户端的网络事件本文通过创建新的线程来监听的。并不会影响客户端主线程的执行,因此可以尽情的阻塞。部分代码如下:

# AsynCallback.py
class AsyncTaskManager(object):
    _asy_events = dict()

    def __init__(self, loop, *args):
        super(AsyncTaskManager, self).__init__()
        self._loop_fun = loop

    def __call__(self, *args, **kwargs):
        proc = threading.Thread(target=self._exec_loop, args=args, kwargs=kwargs)
        proc.start()

    def _exec_loop(self, *args, **kwargs):
        while True:
            net_resp = self._loop_fun(*args, **kwargs)
            for resp in net_resp:
                asy_event = self._asy_events.pop(resp.rid)
                asy_event.set()
# Client.py
class Client(TaskHandle, ClientBase):

    @AsyncTaskManager
    def process(self):
        super(Client, self).process()
        _events = []
        while self.has_events:
            event = self.get_next_event()
            data = event[1]
            _events.append(self.unpack_respond(data))
        return _events

序列化方式,本文采用了库pickle进行序列化与反序列化,使用它的原因是可以将自定义类对象也进行序列化,非常之高级。

2. 异步回调实现思路

对于需要返回值的函数调用,处理起来比较简单,只需要将主线程阻塞等待,直至超时或者接收到了对应函数的返回值即可。本文采用了threading.Event来阻塞与唤醒调用的函数,同时采用了装饰器来实现这功能。若日后有更好的方法,可以轻易进行替换。相关示例代码如下所示:

@AsyncTaskManager.respond
def _handle_response(self, tid):
    """ 处理有返回值的情况
    会阻塞线程直至收到返回值
    """
    task = self.pop_task(tid)
    if task.callback:
        task.callback()
    return self.pop_respond(tid)

@staticmethod
def respond(func):
    @wraps(func)
    def make_resp(handle, tid):
        """ 需要注意的是,和装饰的函数参数含义需一致 """
        event = threading.Event()
        AsyncTaskManager._asy_events[tid] = event
        event.wait(timeout=TIME_OUT)
        return func(handle, tid)    # 这儿才是真正执行_handle_response的地方
    return make_resp

在实际的应用过程中,应有这样的情况,服务端与客户端都是独立的应用,通过rpc函数进行通信和交互,而并不是某方为另外一方提供服务,那么此时返回值并不必要,只需要将要做的事通知另一方即可。对于此种情况,可以采用异步回调的方式来告知调用方对应函数执行成功了。

在文中依旧采用线程来完成该功能,客户端调用函数之后创建一个新线程并阻塞住,等待服务端将执行结果发回后再唤醒,如果有回调函数就执行。示例代码如下:

@AsyncTaskManager.callback
def _handle_call_back(self, tid):
    """ 处理有回调函数的调用
    callback会等tid事件调用成功之后 才会回调,且不会有返回值
    """
    task = self.pop_task(tid)
    if task.callback:
        task.callback()
        
@staticmethod
def callback(func):
    @wraps(func)
    def make_thread(event, *args, **kwargs):
        event.wait(timeout=TIME_OUT)
        func(*args, **kwargs)

    def make_async(handle, tid):
        """ 注意点同上 """
        event = threading.Event()
        AsyncTaskManager._asy_events[tid] = event
        _task = threading.Thread(target=lambda: make_thread(event, handle, tid))

    return make_async

总结

到此这篇关于基于python实现rpc远程过程调用的文章就介绍到这了,更多相关python rpc远程调用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python中实现远程调用(RPC、RMI)简单例子

    远程调用使得调用远程服务器的对象.方法的方式就和调用本地对象.方法的方式差不多,因为我们通过网络编程把这些都隐藏起来了.远程调用是分布式系统的基础. 远程调用一般分为两种,远程过程调用(RPC)和远程方法调用(RMI). RPC RPC属于函数级别的远程调用,其多是通过HTTP传输数据,数据形式有XML.JSON.序列化数据等.在此,用python做一个xml-rpc的示例. 先给服务器端server.py: 复制代码 代码如下: from SimpleXMLRPCServer import S

  • python远程调用rpc模块xmlrpclib的方法

    RPC(Remote Procedure Call Protocol)是远程调用协议,它通过网络请求服务到远端服务器,服务器根据请求做出响应,将结果返回 它是一种C/S模式,客户端可以调用远程服务器上的参数(类似URL)并返回结果 利用rpc可以实现系统的分布式架构,可以将功能分解到多台服务器上进行实现,同时也将也可以将负载打散,分布到不同服务器上,整合计算资源 在openstack中就大量使用了rpc rpc多使用http传输请求,格式有xml,json等,这里是xml 模块: xmlrpcl

  • 基于python实现rpc远程过程调用

    目录 基于python实现RPC的demo 前言 一.主要内容 二.实现步骤 1. 进程间的通信 2. 异步回调实现思路 总结 基于python实现RPC的demo 这是一个远程过程调用(RPC)的实现demo,可以实现不同的python进程之间通信和互相调用函数,简单易用,易于扩展.更多功能也可进一步完善,本文介绍了该实现的主要思路. 前言 计划手撸一个rpc甚久了,在间歇性push自己下终于完成的差不多了.写这个demo的原因,1)是为了学习与思考下这部分主体功能和实现思路,2)是调包时可以

  • 基于python实现雪花算法过程详解

    这篇文章主要介绍了基于python实现雪花算法过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Snowflake是Twitter提出来的一个算法,其目的是生成一个64bit的整数: 1bit:一般是符号位,不做处理 41bit:用来记录时间戳,这里可以记录69年,如果设置好起始时间比如今年是2018年,那么可以用到2089年,到时候怎么办?要是这个系统能用69年,我相信这个系统早都重构了好多次了. 10bit:10bit用来记录机器ID

  • 远程过程调用RPC基本概念及实现原理

    >>什么是RPC RPC 的全称是 Remote Procedure Call 是一种进程间通信方式. 它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节.即无论是调用本地接口/服务的还是远程的接口/服务,本质上编写的调用代码基本相同. 比如两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数或者方法,由于不在一个内存空间,不能直接调用,这时候需要通过就可以应用RPC框架的实现来解决. >>RES

  • Python如何实现远程方法调用

    问题 你想在一个消息传输层如 sockets .multiprocessing connections 或 ZeroMQ 的基础之上实现一个简单的远程过程调用(RPC). 解决方案 将函数请求.参数和返回值使用pickle编码后,在不同的解释器直接传送pickle字节字符串,可以很容易的实现RPC. 下面是一个简单的PRC处理器,可以被整合到一个服务器中去: # rpcserver.py import pickle class RPCHandler: def __init__(self): se

  • MAC平台基于Python Appium环境搭建过程图解

    前言 最近笔者要为python+appium课程做准备,mac在2019年重新安装了一次系统,这次重新在mac下搭建appium环境,刚好顺带写个文稿给大家分享分享搭建过程. 一.环境和所需软件概述 1.1 目前环境: MacOS(10.15.3) 1.2 所需软件: jdk-8u91-macosx-x64.dmg (jdk1.8及以上版本应该都可以) android-sdk_r24.4.1-macosx.zip (mac版本的android-sdk) genymotion-3.0.4.dmg

  • 基于python实现操作git过程代码解析

    安装 pip3 install gitpython 基本使用 # 从远处仓库下载代码到本地 import os from git.repo import Repo # 创建本地存储地址 download_path = os.path.join('jason','NB') # 从远程仓库下载代码 Repo.clone_from('https://github.com/DominicJi/TeachTest.git',to_path=download_path,branch='master') 常用

  • 基于Python实现签到脚本过程解析

    无聊刷日剧,看到签到断了好久,简单写了个脚本,通过模拟抓包的方式实现 1.先登录到字幕组网站获取token 2.用获取到的token登录到人人活动页面获取cookie 3.用获取到的cookie进行签到 import requests import json import time def main(): # 登录,获取用户信息 info = json.loads(get_token()) uid,token = info['data']['uid'],info['data']['token']

  • Python XML RPC服务器端和客户端实例

    一.远程过程调用RPC XML-RPC is a Remote Procedure Call method that uses XML passed via HTTP as a transport. With it, a client can call methods with parameters on a remote server (the server is named by a URI) and get back structured data. This module support

  • 基于Spring的RPC通讯模型的使用与比较

    一.概念和原理 RPC(remote procedure call),远程过程调用,是客户端应用和服务端之间的会话.在客户端,它所需要的一些功能并不在该应用的实现范围之内,所以应用要向提供这些功能的其他系统寻求帮助.而远程应用通过远程服务暴露这些功能.RPC 是同步操作,会阻塞调用代码的执行,直到被调用的过程执行完毕. Spring支持多种不同的RPC模型,包括RMI.Caucho的Hessian和Burlap以及Spring自带的HTTP invoker: 客户端: 在所有的模型中,服务都是作

  • Python使用RPC例子

    目录 主要内容 远程过程调用RPC常用与分布式计算,对应Python库名为rpyc: 上段为rpyc服务端,下段为rpyc调用端: 主要内容 所谓RPC,是远程过程调用(Remote Procedure Call)的简写,网上解释很多,简单来说,就是在当前进程调用其他进程的函数时,体验就像是调用本地写的函数一般. 本文实现的是在本地调用远端的类class对象的接口,也就是本地的client不实例化类对象,调用的是server端的类对象接口. 为了达到让调用层无须关心底层实现,拥有丝滑般的体验,就

随机推荐