gRPC python封装深度学习算法教程

系统 1838 0

最近需要提供一个包含多个神经网络推理的python代码供gRPC调用,即我需要在这个主程序的基础上封装一个支持gRPC的服务端(server)。本教程的目的在于通过简单的代码,来帮助有需求的朋友使用python来构建属于自己的gRPC服务端/客户端。

0. 前言

最近需要用grpc调用我们的算法模块, 对于我来讲,就是需要提供一个grpc的server,供它们的go或者c++的client进行消费。那么, 在python里面如何定义一个完整的server–client,并且使其跑的非常好是个很重要的任务。

1. gRPC的官方介绍

中文官网的python接口例子直接放在grpc的github中,可能需要我们进一步的挖掘,这里,为了避免繁琐,我将通过一个简单的例子来说明如何将我们的任务封装为gRPC的 服务端 (server),并开启 客户端 (client)对其进行调用。

在此之前,先简单介绍一下什么是gRPC:

1.1 什么是gRPC
  • gRPC 是一个高性能、开源和通用的 RPC(远程过程调用) 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持.
    gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

  • 在 gRPC 里客户端(client)应用可以像调用本地对象一样直接调用另一台不同的机器上服务端(server)应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念: ① 定义一个服务 ② 指定其能够被远程调用的方法(包含参数和返回类型) ③ 在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。 在客户端拥有一个 存根(stub) 能够像服务端一样的方法。

gRPC python封装深度学习算法教程_第1张图片

  • gRPC 客户端和服务端可以在多种环境中运行和交互 - 从 google 内部的服务器到你自己的笔记本,并且可以用任何 gRPC 支持的语言来编写。所以,你可以很容易地用 Java 创建一个 gRPC 服务端,用 Go、Python、Ruby 来创建客户端。此外,Google 最新 API 将有 gRPC 版本的接口,使你很容易地将 Google 的功能集成到你的应用里。
1.2 使用 protocol buffers

gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON)。正如你将在下方例子里所看到的,你用 proto files 创建 gRPC 服务,用 protocol buffers 消息类型来定义方法参数和返回类型。你可以在 Protocol Buffers 文档找到更多关于 Protocol Buffers 的资料。
Protocol buffers 版本
尽管 protocol buffers 对于开源用户来说已经存在了一段时间,例子内使用的却一种名叫 proto3 的新风格的 protocol buffers,它拥有轻量简化的语法、一些有用的新功能,并且支持更多新语言。当前针对 Java 和 C++ 发布了 beta 版本,针对 JavaNano(即 Android Java)发布 alpha 版本,在protocol buffers Github 源码库里有 Ruby 支持, 在golang/protobuf Github 源码库里还有针对 Go 语言的生成器, 对更多语言的支持正在开发中。 你可以在 proto3 语言指南里找到更多内容, 在与当前默认版本的发布说明比较,看到两者的主要不同点。更多关于 proto3 的文档很快就会出现。虽然你可以使用 proto2 (当前默认的 protocol buffers 版本), 我们通常建议你在 gRPC 里使用 proto3,因为这样你可以使用 gRPC 支持全部范围的的语言,并且能避免 proto2 客户端与 proto3 服务端交互时出现的兼容性问题,反之亦然。

ps: 我这里使用的都是 protobuf 作为gRPC约定的中间数据传输格式定义。虽然可以用json,但是我没看到这方面的教程。

2. 基本步骤

因为官方教程有比较全面的grpc的各语言接口的安装教程,我这里以python为例,来说明对深度学习应用,我们应该如何搭建一个基于grpc的server–client。

第1步:定义服务(实现自己的hellogdh.proto)

一个 RPC 服务通过参数和返回类型来指定可以远程调用的方法,gRPC 通过 protocol buffers 来实现。使用 protocol buffers 接口定义语言来定义服务方法,用 protocol buffer 来定义参数和返回类型。客户端和服务端均使用服务定义生成的接口代码。

本文的 hellogdh.proto 定义如下[2]:

            
              
                // Copyright 2015 gRPC authors.
              
              
                //
              
              
                // Licensed under the Apache License, Version 2.0 (the "License");
              
              
                // you may not use this file except in compliance with the License.
              
              
                // You may obtain a copy of the License at
              
              
                //
              
              
                //     http://www.apache.org/licenses/LICENSE-2.0
              
              
                //
              
              
                // Unless required by applicable law or agreed to in writing, software
              
              
                // distributed under the License is distributed on an "AS IS" BASIS,
              
              
                // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
              
              
                // See the License for the specific language governing permissions and
              
              
                // limitations under the License.
              
              
                // 参考资料:python版gRPC快速入门一
              
              
                // https://blog.csdn.net/Eric_lmy/article/details/81355322
              
              
syntax 
              
                =
              
              
                "proto3"
              
              
                ;
              
              

option java_multiple_files 
              
                =
              
              
                true
              
              
                ;
              
              
option java_package 
              
                =
              
              
                "io.grpc.gdh.proto"
              
              
                ;
              
              
option java_outer_classname 
              
                =
              
              
                "GdhProto"
              
              
                ;
              
              
option objc_class_prefix 
              
                =
              
              
                "HLW"
              
              
                ;
              
              
                package
              
               hellogdh
              
                ;
              
              
                // 定义服务.
              
              
service Greeter 
              
                {
              
              
                // ① 简单rpc.
              
              
  rpc 
              
                SayHello
              
              
                (
              
              HelloRequest
              
                )
              
              
                returns
              
              
                (
              
              HelloReply
              
                )
              
              
                {
              
              
                }
              
              
                // ② 应答式流rpc.
              
              
  rpc 
              
                LstSayHello
              
              
                (
              
              HelloRequest
              
                )
              
              
                returns
              
              
                (
              
              stream HelloReply
              
                )
              
              
                {
              
              
                }
              
              
                }
              
              
                // 客户端传的消息: HelloRequest.
              
              
message HelloRequest 
              
                {
              
              
  string name 
              
                =
              
              
                1
              
              
                ;
              
              
                }
              
              
                // 服务端发送的消息: HelloReply.
              
              
                // 不能使用int, 只能使用int32这种.
              
              
                // 1, 2, 3表示顺序.
              
              
message HelloReply 
              
                {
              
              
  int32 num_people 
              
                =
              
              
                1
              
              
                ;
              
              
                // repeated 定义列表对应的结构.
              
              
  repeated int32 point 
              
                =
              
              
                2
              
              
                ;
              
              
                }
              
            
          

其中, syntax = "proto3" 表示使用proto3版本。option相关的东西我都没咋动; service Greeter 的意思是定义了一个叫做 Greeter 的服务。这个服务下面有两种,关于gRPC可以定义的服务有4种,下面会详细说明。

定义完毕之后,生成client和server的代码(Note: 我之前以为client和server的代码是自己写的,实际实践后才知道,是根据xxx.proto生成的!!根本不需要我们自己写!

执行这一步需要安装好一些工具如下:

            
              sudo apt-get install protobuf-compiler-grpc 
sudo apt-get install protobuf-compiler

            
          

对我的环境(ubuntu18.04 python3.6) 执行:

protoc -I ./grpc --python_out=./grpc --grpc_out=./grpc --plugin=protoc-gen-grpc=`which grpc_python_plugin` hellogdh.proto

在对应的目录下回生成两个文件 hellogdh_pb2_grpc.py hellogdh_pb2.py

其中, hellogdh_pb2.py包括:

  • 定义在hellogdh.proto中的消息类(Message)
  • 定义在hellogdh.proto中的服务的抽象类:
    BetaHellogdhServicer , 定义了Hellogdh 服务实现的 接口
    BetaHellogdhStub , 定义了可以被客户端用来激活的Hellogdh RPC的 存根
  • 应用到的函数:
    beta_create_Hellogdh_server: 根据BetaHellogdhServicer对象创建一个gRPC服务器(server专用)。
    beta_create_Hellogdh_stub: 客户端用于创建存根stub(client专用)。
第2步:实现server部分代码.

本部分分别以 简单调用(单项RPC) 服务端流RPC 为例进行说明,实际上,gRPC允许4种类型服务方法(如果想完整的学习,还是建议看官方文档的例子[1]):

gRPC python封装深度学习算法教程_第2张图片
gRPC python封装深度学习算法教程_第3张图片
对我而言,因为我需要把多进程的python程序的最后输出队列封装给gRPC的server进程, 所以我首先需要把待处理的队列(Queue)传入gRPC server的进程,再在这个进程中定义好overwrite一些helloworld_pb2.py的方法。

最后,在主进程中启动所有的神经网络任务进程和gRPC进程,并 阻塞 (join(),join的作用是保证当前进程正常结束, 即不会因为主进程先退出而把未执行完的子进程kill掉。)。

代码如下,参考自github grpc/examples/python 下的 route_guide

            
              
                import
              
               sys
sys
              
                .
              
              path
              
                .
              
              append
              
                (
              
              
                ".."
              
              
                )
              
              
                import
              
               grpc

              
                import
              
               hellogdh_pb2

              
                import
              
               hellogdh_pb2_grpc

              
                from
              
               concurrent 
              
                import
              
               futures


              
                import
              
               cv2

              
                import
              
               time

              
                import
              
               numpy 
              
                as
              
               np

              
                from
              
               utils
              
                .
              
              config 
              
                import
              
              
                *
              
              
                import
              
               logging

              
                from
              
               capture 
              
                import
              
               queue_put
              
                ,
              
               queue_get
              
                ,
              
               queue_img_put

              
                from
              
               module
              
                .
              
              Worker 
              
                import
              
               PoseWorker

              
                import
              
               multiprocessing 
              
                as
              
               mp

              
                from
              
               multiprocessing 
              
                import
              
               Pool
              
                ,
              
               Queue
              
                ,
              
               Lock



              
                # 0.0 grpc.
              
              
                def
              
              
                grpc_server
              
              
                (
              
              queue
              
                )
              
              
                :
              
              
                class
              
              
                gdhServicer
              
              
                (
              
              hellogdh_pb2
              
                .
              
              BetaGreeterServicer
              
                )
              
              
                :
              
              
                def
              
              
                SayHello
              
              
                (
              
              self
              
                ,
              
               request
              
                ,
              
               context
              
                )
              
              
                :
              
              
                # Note: 传参的时候必须要显式指定参数名称, 而不能lynxi_pb2.HelloReply(1, [5, 10])
              
              
                if
              
               request
              
                .
              
              name 
              
                ==
              
              
                'gdh'
              
              
                :
              
              
                return
              
               hellogdh_pb2
              
                .
              
              HelloReply
              
                (
              
              num_people
              
                =
              
              
                1
              
              
                ,
              
               point
              
                =
              
              
                [
              
              
                1
              
              
                ,
              
              
                1
              
              
                ]
              
              
                )
              
              
                else
              
              
                :
              
              
                return
              
               hellogdh_pb2
              
                .
              
              HelloReply
              
                (
              
              num_people
              
                =
              
              
                55
              
              
                ,
              
               point
              
                =
              
              
                [
              
              
                1
              
              
                ,
              
              
                1
              
              
                ]
              
              
                )
              
              
                def
              
              
                LstSayHello
              
              
                (
              
              self
              
                ,
              
               request
              
                ,
              
               context
              
                )
              
              
                :
              
              
                while
              
               request
              
                .
              
              name 
              
                ==
              
              
                'gdh'
              
              
                :
              
              
                data 
              
                =
              
               queue
              
                .
              
              get
              
                (
              
              
                )
              
              
                # 因为是服务端流式模式,所以用yield。
              
              
                yield
              
               hellogdh_pb2
              
                .
              
              HelloReply
              
                (
              
              num_people
              
                =
              
              data
              
                .
              
              num
              
                ,
              
               point
              
                =
              
              
                [
              
              data
              
                .
              
              point
              
                [
              
              
                0
              
              
                ]
              
              
                ,
              
               data
              
                .
              
              point
              
                [
              
              
                1
              
              
                ]
              
              
                ]
              
              
                )
              
              
                # 1. 之前启动server的方式.
              
              
                # server = helloworld_gdh_pb2.beta_create_Greeter_server(gdhServicer())
              
              
                # 2. 在route_guide里面学到的启动server的方式.
              
              
    server 
              
                =
              
               grpc
              
                .
              
              server
              
                (
              
              futures
              
                .
              
              ThreadPoolExecutor
              
                (
              
              max_workers
              
                =
              
              
                10
              
              
                )
              
              
                )
              
              
    lynxi_pb2_grpc
              
                .
              
              add_GreeterServicer_to_server
              
                (
              
              gdhServicer
              
                (
              
              
                )
              
              
                ,
              
               server
              
                )
              
              
    server
              
                .
              
              add_insecure_port
              
                (
              
              
                '[::]:50051'
              
              
                )
              
              
                # 因为 start() 不会阻塞,如果运行时你的代码没有其它的事情可做,你可能需要循环等待。
              
              
    server
              
                .
              
              start
              
                (
              
              
                )
              
              
                try
              
              
                :
              
              
                while
              
              
                True
              
              
                :
              
              
                # time.sleep(_ONE_DAY_IN_SECONDS)
              
              
            time
              
                .
              
              sleep
              
                (
              
              
                5
              
              
                )
              
              
                except
              
               KeyboardInterrupt
              
                :
              
              
        server
              
                .
              
              stop
              
                (
              
              
                )
              
              
                # 2.1 对每个任务建立一个队列.
              
              
pose_queue_raw 
              
                =
              
               Queue
              
                (
              
              
                )
              
              
monitor_queue_raw 
              
                =
              
               Queue
              
                (
              
              
                )
              
              
pose_out_queue 
              
                =
              
               Queue
              
                (
              
              
                )
              
              
                # key: 名称, val[0]: 队列, val[1]: 加载好的模型.
              
              
queues 
              
                =
              
              
                {
              
              
                'pose'
              
              
                :
              
               pose_queue_raw
              
                ,
              
              
                'monitor'
              
              
                :
              
               monitor_queue_raw
              
                }
              
              
                #                     pose
              
              
                #                  /
              
              
                #                 /
              
              
                # 3. 生产者-消费者 ---  detect
              
              
                #                 \
              
              
                #                  \
              
              
                #                     face_detect
              
              

processes 
              
                =
              
              
                [
              
              
                ]
              
              
                for
              
               key
              
                ,
              
               val 
              
                in
              
               queues
              
                .
              
              items
              
                (
              
              
                )
              
              
                :
              
              
    processes
              
                .
              
              append
              
                (
              
              mp
              
                .
              
              Process
              
                (
              
              target
              
                =
              
              queue_put
              
                ,
              
               args
              
                =
              
              
                (
              
              val
              
                ,
              
              
                )
              
              
                )
              
              
                )
              
              
                if
              
               key 
              
                ==
              
              
                'pose'
              
              
                :
              
              
        processes
              
                .
              
              append
              
                (
              
              PoseWorker
              
                (
              
              val
              
                ,
              
               pose_out_queue
              
                )
              
              
                )
              
              
                else
              
              
                :
              
              
        processes
              
                .
              
              append
              
                (
              
              mp
              
                .
              
              Process
              
                (
              
              target
              
                =
              
              queue_get
              
                ,
              
               args
              
                =
              
              
                (
              
              val
              
                ,
              
              
                )
              
              
                )
              
              
                )
              
              


processes
              
                .
              
              append
              
                (
              
              mp
              
                .
              
              Process
              
                (
              
              target
              
                =
              
              grpc_server
              
                ,
              
               args
              
                =
              
              
                (
              
              pose_out_queue
              
                ,
              
              
                )
              
              
                )
              
              
                )
              
              
                [
              
              process
              
                .
              
              start
              
                (
              
              
                )
              
              
                for
              
               process 
              
                in
              
               processes
              
                ]
              
              
                [
              
              process
              
                .
              
              join
              
                (
              
              
                )
              
              
                for
              
               process 
              
                in
              
               processes
              
                ]
              
            
          

这段代码的意思是将PoseWorker处理得到的队列 pose_out_queue 喂给gRPC server进程,并设置好根据client发来的请求来发送处理好的数据。 queue_put queue_get 是将视频的帧封装后放入队列A和从队列A中读取并显示的函数。

            
              
                import
              
               cv2

              
                from
              
               multiprocessing 
              
                import
              
               Queue
              
                ,
              
               Process

              
                from
              
               PIL 
              
                import
              
               Image
              
                ,
              
               ImageFont
              
                ,
              
               ImageDraw

              
                import
              
               cv2


              
                def
              
              
                queue_put
              
              
                (
              
              q
              
                ,
              
               video_name
              
                =
              
              
                "/home/samuel/gaodaiheng/handup.mp4"
              
              
                )
              
              
                :
              
              
    cap 
              
                =
              
               cv2
              
                .
              
              VideoCapture
              
                (
              
              video_name
              
                )
              
              
                while
              
              
                True
              
              
                :
              
              
        is_opened
              
                ,
              
               frame 
              
                =
              
               cap
              
                .
              
              read
              
                (
              
              
                )
              
              
        q
              
                .
              
              put
              
                (
              
              frame
              
                )
              
              
                if
              
               is_opened 
              
                else
              
              
                None
              
              
                def
              
              
                queue_get
              
              
                (
              
              q
              
                ,
              
               window_name
              
                =
              
              
                'image'
              
              
                )
              
              
                :
              
              
    cv2
              
                .
              
              namedWindow
              
                (
              
              window_name
              
                ,
              
               flags
              
                =
              
              cv2
              
                .
              
              WINDOW_NORMAL
              
                )
              
              
                while
              
              
                True
              
              
                :
              
              
        frame 
              
                =
              
               q
              
                .
              
              get
              
                (
              
              
                )
              
              
        cv2
              
                .
              
              imshow
              
                (
              
              window_name
              
                ,
              
               frame
              
                )
              
              
        cv2
              
                .
              
              waitKey
              
                (
              
              
                1
              
              
                )
              
            
          

需要额外注意的是,PoseWorker是继承 multiprocessing.Process 类的进程,其大体定义如下:

            
              
                from
              
               multiprocessing 
              
                import
              
               Queue
              
                ,
              
               Process


              
                class
              
              
                PoseWorker
              
              
                (
              
              Process
              
                )
              
              
                :
              
              
                """
        Pose estimation姿态估计.
    """
              
              
                def
              
              
                __init__
              
              
                (
              
              self
              
                ,
              
               queue
              
                ,
              
               out_queue
              
                )
              
              
                :
              
              
        Process
              
                .
              
              __init__
              
                (
              
              self
              
                ,
              
               name
              
                =
              
              
                'PoseProcessor'
              
              
                )
              
              
                # 输入队列和输出队列.
              
              
        self
              
                .
              
              in_queue 
              
                =
              
               queue
        self
              
                .
              
              out_queue 
              
                =
              
               out_queue

    
              
                def
              
              
                run
              
              
                (
              
              self
              
                )
              
              
                :
              
              
                #set enviornment
              
              
        os
              
                .
              
              environ
              
                [
              
              
                "CUDA_VISIBLE_DEVICES"
              
              
                ]
              
              
                =
              
              
                "0"
              
              
                #load models
              
              
                import
              
               tensorflow 
              
                as
              
               tf
        
              
                .
              
              
                .
              
              
                .
              
              
        model 
              
                =
              
               load_model
              
                (
              
              xxx
              
                )
              
              
                .
              
              
                .
              
              
                .
              
              
                while
              
              
                True
              
              
                :
              
              
                # 从入的队列中消费数据.
              
              
        	frame 
              
                =
              
               self
              
                .
              
              in_queue
              
                .
              
              get
              
                (
              
              
                )
              
              
                # 喂入模型推理得到结果.
              
              
            result 
              
                =
              
               model
              
                .
              
              inference
              
                (
              
              frame
              
                )
              
              
                # 将结果放回到生产者中.
              
              
            self
              
                .
              
              out_queue
              
                .
              
              put
              
                (
              
              result
              
                )
              
            
          
第3步:实现server部分代码.

和第2步类似,代码如下,参考自github grpc/examples/python [3]下的 route_guide

            
              
                # coding: UTF-8
              
              
                """
    @author: samuel ko
"""
              
              
                import
              
               os

              
                import
              
               grpc

              
                import
              
               hellogdh_pb2 
              
                as
              
               helloworld_gdh_pb2

              
                import
              
               hellogdh_pb2_grpc 
              
                as
              
               helloworld_gdh_pb2_grpc

              
                import
              
               time

_ONE_DAY_IN_SECONDS 
              
                =
              
              
                60
              
              
                *
              
              
                60
              
              
                *
              
              
                24
              
              
                # 1. 为了能调用服务的方法,我们得先创建一个 存根。
              
              
                # 我们使用 .proto 中生成的 route_guide_pb2 模块的函数beta_create_RouteGuide_stub。
              
              
                def
              
              
                run
              
              
                (
              
              
                )
              
              
                :
              
              
                with
              
               grpc
              
                .
              
              insecure_channel
              
                (
              
              
                'localhost:50051'
              
              
                )
              
              
                as
              
               channel
              
                :
              
              
                # 1) 存根方式1.
              
              
        stub 
              
                =
              
               helloworld_gdh_pb2
              
                .
              
              GreeterStub
              
                (
              
              channel
              
                )
              
              
                # 2) 存根方式2.
              
              
                # stub = helloworld_gdh_pb2_grpc.GreeterStub(channel)
              
              
                print
              
              
                (
              
              
                "-------------- ① 简单RPC --------------"
              
              
                )
              
              
                # response = stub.SayHello(helloworld_gdh_pb2.HelloRequest(name='gdh'))
              
              
        features 
              
                =
              
               stub
              
                .
              
              SayHello
              
                (
              
              helloworld_gdh_pb2
              
                .
              
              HelloRequest
              
                (
              
              name
              
                =
              
              
                'gdh'
              
              
                )
              
              
                )
              
              
                print
              
              
                (
              
              features
              
                )
              
              
                print
              
              
                (
              
              
                "-------------- ② 服务端流式RPC --------------"
              
              
                )
              
              
        features 
              
                =
              
               stub
              
                .
              
              LstSayHello
              
                (
              
              helloworld_gdh_pb2
              
                .
              
              HelloRequest
              
                (
              
              name
              
                =
              
              
                'gdh'
              
              
                )
              
              
                )
              
              
                for
              
               feature 
              
                in
              
               features
              
                :
              
              
                print
              
              
                (
              
              
                "哈哈哈 %s at %s, %s"
              
              
                %
              
              
                (
              
              feature
              
                .
              
              num_people
              
                ,
              
               feature
              
                .
              
              point
              
                [
              
              
                0
              
              
                ]
              
              
                ,
              
               feature
              
                .
              
              point
              
                [
              
              
                1
              
              
                ]
              
              
                )
              
              
                )
              
              
                if
              
               __name__ 
              
                ==
              
              
                "__main__"
              
              
                :
              
              
    run
              
                (
              
              
                )
              
            
          

最后,就会打印出符合我们服务端设定的数据结构…

补充知识:protobuf 支持的python数据结构.

在proto的Message定义中, 我们支持python的string等类型, 在proto中需要显式标明, 我推测是 由于gRPC是支持多种语言接口的,有些语言是 强类型 的(C/C++, Go),所以务必需要显式标明数据类型, 避免带来不必要的麻烦 :

            
              message HelloRequest {
  string name = 1;
}

            
          

其中, 1, 2, 3表示的是参数的顺序. 我们支持的数据类型如下:

  • string
  • float
  • int32 / uint32 (不支持int16和int8)
  • bool
  • repeated int以及我们自定义的Message.
    这里需要特别强调, repeated 表示不定长的数组, 里面可以放built-in的类型,或者自己额外封装的message. 很灵活. 对应python的list.
            
              	message BoxInfos 
              
                {
              
              
	    message BoxInfo 
              
                {
              
              
	        uint32 x0 
              
                =
              
              
                1
              
              
                ;
              
              
	        uint32 y0 
              
                =
              
              
                2
              
              
                ;
              
              
	        uint32 x1 
              
                =
              
              
                3
              
              
                ;
              
              
	        uint32 y1 
              
                =
              
              
                4
              
              
                ;
              
              
                }
              
              
    repeated BoxInfo boxInfos 
              
                =
              
              
                1
              
              
                ;
              
              
                }
              
            
          
  • bytes 字节流, 可以用于传递图片. 不过一般性在gRPC中, 每条消息的大小都不大(1MB左右?) 所以一般性都是传图片的绝对路径?
  • map 字典,对应python的dict, 不过需要显式指定key和value的类型.

总结

截至目前,一个封装多进程神经网络算法的python版 gRPC server-client就已经圆满完成, 因为我也是刚接触,可能有理解上的偏差,恳请各位指正, 非常感谢~

参考资料

[1] gRPC–python中文官网
[2] python版gRPC快速入门一
[3] grpc/examples/python


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论