高效性跨平台分布式软件开发技术——gRPC

文章目录

        • 1. gRPC(google Remote Procedure Call) 技术 —— 高效性地跨平台、跨语言开发
        • 2. 基于 python 实现 gRPC 框架
          • 2.1 一个 gPRC 项目必须包含的几大部分
          • 2.2 helloworld.proto 文件——定义全局可调用函数及其参数数据结构
          • 2.3 server.py 文件——实现服务器端的全局可调用函数
          • 2.4 client.py 文件——调用在服务器代码中实现的全局函数
          • 2.5 运行结果
        • 3. 基于gRPC技术搭建一个简单的Agent学习系统

相信不少人在做项目开发的时候都会遇到这样的问题:一套系统中不同部分的代码会部署在多个不同的设备平台上,多个平台间需要保证数据相连。对于分布式部署的系统来说,高效的通信直接决定了整个系统的性能。此外,由于平台的多样性,不同平台上所适合的编程语言也可能有所差异(如:c++、python、objective-c等)。为此,一门支持“跨平台”、“跨语言”的技术对于一个分布式部署的系统来说显得尤为重要。

1. gRPC(google Remote Procedure Call) 技术 —— 高效性地跨平台、跨语言开发

为了解决上述问题,google设计了一种远程系统调用技术,其将多个不同设备平台视为一个整体,保证了在一个设备上的代码能够对另一个设备上代码中的函数进行访问和调用,实现了多个平台之间的数据交互,且各设备间不需要约定使用同一种编程语言,这就是gRPC技术。例如,在服务器机器上使用c++实现好的函数,在客户端终端设备上可以直接使用Ruby调用,在另外一台客户端机器上也可以直接使用Android调用,很好的保证了“跨语言、跨平台”的开发流程。

要想实现跨平台的代码调用就必然涉及到平台间的数据通信问题,数据通信效率成为了系统性能的一个重要指标。gRPC基于protobuf设计了数据互通协议,保证了数据传输时的高效性和快速性。Protocol Buffers是一种数据格式,与XML、JSON类似,但比JSON和XML更加的高效和快速,在一些高性能且对响应速度有要求的数据传输场景非常适用。在使用JSON进行数据编译时,为了保证数据的易读性JSON是以文本的形式存储和传输的,这样一来导致进行数据交换时设备需要耗费大量的CPU在I/O动作上,从而影响整个传输速率。而protobuf不同于JSON,它会将字符串都进行序列化后再进行传输,即传输的是二进制数据,此外,protobuf是基于数字tag来标识各内容,而JSON则是以字符串来标识各内容的,因此protobuf在传输速率方面有着天然的优势。

// protobuf 基于数字来确定内容段
message Person {required string name = 1;required int32 age = 2;required string gender = 3; 
}// Json 基于字符串来确定内容段
{"name" : "Wang DaChui","age"  : "18","gender" : "Male"
}

2. 基于 python 实现 gRPC 框架

如上一节中的图片中所示,我们可以利用gRPC框架实现不同平台上的代码之间相互调用,这一节中,我们通过分别编写“服务器”和“客户端”这两个不同平台的代码来实现在客户端代码中调用服务器代码中的函数。为了编写方便,我们将服务器和客户端代码存放在同一个机器上的不同位置,等最后部署的时候再将代码分别部署到对应的设备平台上。

2.1 一个 gPRC 项目必须包含的几大部分

下图是一个最简单的 gRPC 项目需要包含的文件,我们先来看看这些文件分别有什么用:

  • helloworld.proto:该文件的作用是“定义服务器函数” + “定义函数参数的数据类型”。
  • helloworld_pb2.pyhelloworld_pb2_grpc.py: 这两个文件是由python的grpc_tools根据helloworld.proto文件自动生成的,这两个文件保证了客户端能够调用服务器端的函数,不用修改。
  • server.py:服务器(设备平台1)上的代码。
  • client.py:客户端(设备平台2)上的代码。

上述4个部分是一个最简单的grpc项目所包含的文件,接下来我们依次实现每一个部分中代码,搭建一个简单的grpc项目,使得我们能够在client.py代码中调用server.py中定义的函数。这里可能有人会有疑问,如果要让client.py能调用server.py中的函数,那直接把server.py写成一个类,再在client.py中import server不就好了吗?需要注意的是,在最终部署的时候server.py和client.py是会部署在不同的机器上的,那时候client.py的机器上是找不到server.py代码文件的,这里只是为了方便开发和讲解才把这两个文件放在同一个机器上。

2.2 helloworld.proto 文件——定义全局可调用函数及其参数数据结构

.proto文件中需要定义服务器中需要实现的全局可调用函数,以及这个函数的参数数据结构,由于我们想在服务器上实现一个客户端可以直接调用的加法器,那么在.proto文件中我们就需要明确定义这个“加法函数”,以及“加法函数”所接收的参数类型和返回值类型,helloworld.proto文件内容如下:

syntax = "proto3";service Adder{// 将全局可调用函数AddNumber在这里声明,第一个括号内是传入参数,第二个括号是返回值参数rpc AddNumber(AddRequest) returns (AddResponse) {}
}// 对全局函数AddNumber的输入参数AddRequest进行数据格式定义
message AddRequest{int32 Number1 = 1;int32 Number2 = 2;
}// 对全局函数AddNumber的返回值参数AddResponse进行数据格式定义
message AddResponse{string ResultString = 1;
}

编写完成后保存文件,在Terminal中运行:

python -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./helloworld.proto

运行成功后会在当前目录生成两个文件:helloworld_pb2.pyhelloworld_pb2_grpc.py

  • –python_out:该参数指定了helloworld_pb2.py文件的生成路径。
  • –grpc_python_out:该参数指定了helloworld_pb2_grpc.py文件的生成路径。
  • -I:该参数指定了.proto文件的存放路径。
  • ./helloworld.proto:.proto文件的文件名。
2.3 server.py 文件——实现服务器端的全局可调用函数

server.py文件用于实现在.proto文件中声明的那些全局可调用函数,例如我们在helloworld.proto文件中声明了一个AddNumber()函数,那么我们就需要在server.py文件中去亲自实现这个函数,server.py文件内容如下:

from concurrent import futures
import loggingimport grpcimport helloworld_pb2
import helloworld_pb2_grpc"""对应.proto文件中的service Adder类"""
class Adder(helloworld_pb2_grpc.AdderServicer):"""实现.proto文件中的AdderNumber函数,这里request参数类型和.proto文件中AddRequest类型一样"""def AddNumber(self, request, context):"""保证该函数的返回值和.proto文件中定义的AddResponse返回值类型一样"""return helloworld_pb2.AddResponse(ResultString="Result: %d" % (request.Number1 + request.Number2))def serve():server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))helloworld_pb2_grpc.add_AdderServicer_to_server(Adder(), server)server.add_insecure_port('[::]:50051')server.start()server.wait_for_termination()if __name__ == "__main__":logging.basicConfig()serve() 

在这个文件中最重要的部分就是Adder这个类,这个类是对.proto文件中的service Adder的实现,因此在.proto中service部分里定义的函数在这个Adder class中都必须要实现。AddNumber(self, request, context)函数就是其对应的实现,第二个参数request的类型和.proto中定义的AddRequest类型是一样的(这个request参数是在客户端调用这个函数时需要传入的),因此可以直接通过request.Number1 和 request.Number2来直接访问这两个整型数据。最后在函数返回的时候必须要保证值也是.proto中定义的返回值类型,最好的办法就是直接返回.proto文件中的这个对象,只是修改这个对象中的值ResultString即可。

2.4 client.py 文件——调用在服务器代码中实现的全局函数

当我们实现好了server.py中的函数后,我们就可以在客户端代码中调用这个全局函数了,在这里我们在client.py代码中去调用server.py代码中实现的Adder()函数,client.py的内容如下:

import loggingimport grpcimport helloworld_pb2
import helloworld_pb2_grpcdef run():"""建立通信管道"""with grpc.insecure_channel('localhost:50051') as channel:"""建立一个stub对象,通过这个对象我们就可以调用服务器端的函数了"""stub = helloworld_pb2_grpc.AdderStub(channel)"""调用stub.AddNumber()函数,要保证传入参数是.proto文件中的AddRequest对象"""response = stub.AddNumber(helloworld_pb2.AddRequest(Number1=1, Number2=2))print(response)if __name__ == "__main__":logging.basicConfigrun()

在客户端代码中首先要建立一个stub对象,该对象就是远程服务器对象,我们通过stub对象就可以访问远程服务器上实现的全部函数了。要注意的是,在传入参数里必须要和.proto文件中的传入对象完全保持一致,最好的办法还是传入一个.proto文件中所声明的对象,只是修改其中的值便可。

2.5 运行结果

依次在两个不同的Terminal中先后运行server.py和client.py,在client端的运行环境中看到成功调用了server端中的AddNumber()函数:

3. 基于gRPC技术搭建一个简单的Agent学习系统

使用gRPC技术可以方便的设计一个Agent学习系统,即仿真端负责仿真环境的数据计算,算法端负责Agent行为决策。我使用gRPC技术搭建了一个简单的机器人找钻石的学习系统,github地址:这里。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290345.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在VS中设置比较和谐的字体和颜色的方法

作者:朱金灿来源:http://blog.csdn.net/clever101先在studiostyl.es网站选择你喜欢的字体方案,我个人比较喜欢这款:Humane Studio,注意在网页上选择你使用VS版本,然后单击Downlaod this scheme就可以了&…

C和指针之字符串strchr、strpbrk、strstr

1、strchr、strpbrk、strstr 1) char *strchr(const char *s, int c); 在s中找字符c 第一次出现的地方,返回这个指向该位置的指针,没找到返回NULL 2) char *strrchr(const char *s, int c); 在s中最右边找字符c 第一次出现的地方,返回这个指向该位置的指针,没…

一个脚本实现全量增量备份,并推送到远端备份中心服务器

2019独角兽企业重金招聘Python工程师标准>>> 摘要 由于工作需要,刚好需要这样一个功能的脚本,主要解决: 1. 不想在crontab中调度两条备份任务,一个做全量一个做增量 2. 如果每小时做增量,凌晨4点做全量&…

.NET 7 预览版 2 已发布,NativeAOT 正式可用

.NET 7 Preview 2 已发布,第二个预览版包括对 RegEx 源生成器的增强、将 NativeAOT 从实验状态转移到运行时的进展,以及对“dotnet new”CLI SDK 的一系列重大改进。在此下载适用于 Windows、macOS 和 Linux 的 .NET 7 Preview 2 。引入新的正则表达式源…

地壳中元素含量排名记忆口诀_Nature:利用熔融包裹体的元素和同位素示踪俯冲带流体来源...

Nature:利用熔融包裹体的元素和同位素示踪俯冲带流体来源在汇聚板块边缘,大洋岩石圈通过俯冲作用携带挥发分(尤其是水)进入地幔。这些俯冲下去的水/流体控制着岩浆产物、地震活动、陆壳形成和资源成矿。但是,识别不同流体的来源(沉积物&#…

Windows 10开发基础——文件、文件夹和库(一)

Windows 10开发基础——文件、文件夹和库(一) 原文:Windows 10开发基础——文件、文件夹和库(一)主要内容: 1.枚举查询文件和文件夹 2.文本文件读写的三种方法——创建写入和读取文件 3.获得文件的属性 枚举查询文件和…

Sigmoid函数与逻辑回归

文章目录(1). Sigmoid函数的由来——伯努利分布的衍生物1.1 为什么会有 sigmoid 函数的出现?1.2 sigmoid 函数推导过程1.3 sigmoid 函数求导(2). 逻辑回归(Logistic Regression)2.1 逻辑回归算法的最终本质——求决策边界2.2 逻辑回归算法中的…

C和指针之字符串实现strrstr函数

1、问题 实现strrstr(const char *str, const char *str2)函数,就是从最右边开始,找到第一次出现字符str2,然后返回指向这个字符的指针,找不到返回NULL,str2和str1一个为NULL 返回 NULL 2、思路 我们用2个变量, 先用strstr一个变量找一个保存当前地址,然后再用strstr去…

括号匹配

CTRL SHIFTP 括号匹配

react connect

connect([mapStateToProps], [mapDispatchToProps], [mergeProps],[options])连接 React 组件与 Redux store。连接操作不会改变原来的组件类,反而返回一个新的已与 Redux store 连接的组件类。参数[mapStateToProps(state, [ownProps]): stateProps] (Function): 如…

Avalonia跨平台入门第二十二篇之人脸检测

在前面分享的几篇中咱已经玩耍了Popup、ListBox多选、Grid动态分、RadioButton模板、控件的拖放效果、控件的置顶和置底、控件的锁定、自定义Window样式、动画效果、Expander控件、ListBox折叠列表、聊天窗口、ListBox图片消息、窗口抖动、语音发送、语音播放、语音播放问题、玩…

pkpm板按弹性计算还是塑性_PKPM中的S\R验算显红原因分析

PKPM软件砼结构施工图中的,梁的配筋面积中,SR验算,经常会有个别构件显红的情况。查了一下PKPM说明书,并没有针对此情况的详细说明。根据本人的实际经验,总结了一下解决此问题的主要方法:一.超筋SR的值显示为…

C和指针之字符串strspn、strcspn函数源代码的实现

1、strspn strcspn介绍 1)size_t strspn(const char *str, const char * accept); 我的理解是字符串str中前面连续的字符有多少在accept中,如果哪一个没在accept中,就到这里结束了,后面不比了,比如 char *str = "xnufux dfafa"; char accept = "linux"…

StackExchange.Redis 使用 (一)

在StackExchange.Redis中最重要的对象是ConnectionMultiplexer类, 它存在于StackExchange.Redis命名空间中。这个类隐藏了Redis服务的操作细节,ConnectionMultiplexer类做了很多东西, 在所有调用之间它被设计为共享和重用的。不应该为每一个操…

多智能体连续行为空间问题求解——MADDPG

目录1. 问题出现:连续行为空间出现2. DDPG 算法2.1 DDPG 算法原理2.2 DDPG 算法实现代码2.2.1 Actor & Critic2.2.2 Target Network2.2.3 Memory Pool2.2.4 Update Parameters(evaluate network)2.2.5 Update Parameters(targ…

在.NET 6 中如何创建和使用 HTTP 客户端 SDK

如今,基于云、微服务或物联网的应用程序通常依赖于通过网络与其他系统通信。每个服务都在自己的进程中运行,并解决一组有限的问题。服务之间的通信是基于一种轻量级的机制,通常是一个 HTTP 资源 API。从.NET 开发人员的角度来看,我…

C和指针之字符串strtok函数

1、strtok函数 头文件&#xff1a;#include <string.h>定义函数&#xff1a;char * strtok(char *s, const char *delim);函数说明&#xff1a;strtok()用来将字符串分割成一个个片段。参数s 指向欲分割的字符串&#xff0c;参数delim 则为分割字符串&#xff0c;当strto…

#CSS# 初识CSS

CSS&#xff1a;Cascading Style Sheet &#xff08;层叠样式表&#xff09; CSS的内容可以分开写入CSS文件中&#xff0c;PHP文件中加入以下语句即可&#xff1a; <link herf"css/style.css" type"text/css" rel"stylesheet"/> 其中&…

js隐藏div

页面上有一个div&#xff0c;用JQuery隐藏<div id"hid_div" class"divID">解决方法&#xff1a;(1)用js&#xff1a;document.getElementById(hid_div).style.display "none";(2)jQuery:${.divID}.hid();ps:如果用方法&#xff08;1&…

ttl接地是高电平还是低电平_功放技术参数1——高电平

在汽车音响中的功放或者DSP再或者是DSP功放中我们都会遇到高电平信号或者低电平信号输入&#xff0c;我们该如何判断主机输出的到底是高电平信号还是低电平信号呢&#xff1f;我们可以用一个很简单的方法来鉴定&#xff0c;那就是主机输出能够直接驱动喇叭的为高电平信号输出&a…