美文网首页
一个简单的python gRpc (route_guide_si

一个简单的python gRpc (route_guide_si

作者: 飞跑的蛤蟆 | 来源:发表于2021-05-03 22:50 被阅读0次

    route_guide_simple

    这是一个简化版的route_guide,本文参考自gRpc官方文档,略有删改,水平有限翻译不对的地方敬请见谅。

    完整代码地址

    # 生成_pb2.py和_pb2_grpc.py文件
    python -m grpc_tools.protoc -I ./ --python_out . --grpc_python_out . ./route_guide.proto
    

    文件结构以及说明

    ./
    ├── README.md
    ├── route_guide_client.py  # 客户端
    ├── route_guide_db.json  # 提供数据
    ├── route_guide_pb2_grpc.py  # 生成的
    ├── route_guide_pb2.py  # 生成的
    ├── route_guide.proto  # protocol buffer file
    ├── route_guide_resources.py  # 提供数据
    └── route_guide_server.py  # 服务端
    
    • route_guide_client.pyroute_guide_server.py文件分别为客户端和服务端,它们的通信是通过gRpc实现的。
    • route_guide_db.jsonroute_guide_resources.py文件是提供数据的。
    • route_guide.proto文件是protocal buffer file,protobuf是一种接口描述语言(IDL),里面定义了语言无关的数据结构以供其他语言调用。
    • route_guide_pb2.pyroute_guide_pb2_grpc.py是通过protobuf生成的
      • route_guide_pb2定义了messages的数据结构
      • route_guide_pb2_grpc
        • 客户端可以通过RouteGuideStub调用RouteGuideRPC
        • RouteGuideServicer定义了RouteGuide服务的实现接口
        • add_RouteGuideServicer_to_serverRouteGuideServicer添加到grpc.Server

    代码说明

    创建服务器

    实现 RouteGuide :

    gRpc/examples/route_guide_simple/route_guide_server.py 模块中有一个 RouteGuideServicer 类,它继承自 route_guide_pb2_grpc. RouteGuideServicer ,并实现了所有 RouteGuide 方法。

    # RouteGuideServicer provides an implementation of the methods of the RouteGuide service.
    class RouteGuideServicer(route_guide_pb2_grpc.RouteGuideServicer):
    

    Simple RPC

    GetFeature是一个最简单的类型,它仅从客户端获取Point,然后在Feature中返回数据库中相应的feature信息。

    def GetFeature(self, request, context):
        feature = get_feature(self.db, request)
        if feature is None:
            return route_guide_pb2.Feature(name="", location=request)
        else:
            return feature
    

    该方法传递了 route_guide_pb2. Point 请求给RPC,以及一个 grpc. ServicerContext 对象,它提供了RPC特定信息(例如超时限制)。返回一个 route_guide_pb2. Feature 响应。

    gRpc服务器

    def serve():
        server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
        route_guide_pb2_grpc.add_RouteGuideServicer_to_server(
            RouteGuideServicer(), server)
        server.add_insecure_port('[::]:50051')
        server.start()
        server.wait_for_termination()
    

    serverstart() 方法是非阻塞的。将实例化一个新线程来处理请求。在此期间,调用 server.start() 的线程通常不会执行任何其他工作。

    在这种情况下,您可以调用 server.wait_for_termination() 来彻底清除调用线程,直到服务器终止。

    创建客户端

    route_guide_client

    创建存根

    调用服务方法之前,我们要先创建一个存根。

    grpc.insecure_channel('localhost:50051')
    stub = route_guide_pb2_grpc.RouteGuideStub(channel)
    

    我们实例化一个 route_guide_pb2_grpc 模块的 RouteGuideStub 类,它是由 protobuf 文件生成的。

    调用服务方法

    同步:对于返回单一响应的RPC方法 ("response-unary" methods) ,gRPC Python支持同步(阻塞)和异步(非阻塞)控制流语义。同步调用简单的RPC方法 GetFeature 几乎与调用本地方法一样直接。 RPC调用等待服务器响应,并且将返回响应或引发异常:

    feature = stub.GetFeature(point)
    

    异步:对于 GetFeature 的异步调用与此类似,就像在线程池中异步调用本地方法一样:

    feature_future = stub.GetFeature.future(point)
    feature = feature_future.result()
    

    启动服务

    # 启动服务端
    python route_guide_server.py
    # 启动客户端
    python route_guide_client.py
    

    客户端打印结果:

    -------------- GetFeature --------------
    Feature called Berkshire Valley Management Area Trail, Jefferson, NJ, USA at latitude: 409146138
    longitude: -746188906
    
    Found no feature at 
    

    protoc生成的代码

    gRpc Python 依赖于协议缓冲编译器(protoc)来生成代码。它使用插件通过 gRPC-specific 代码通过 plain protoc 来补充所生成的代码。对于包含gRPC服务的.proto服务描述, plain protoc 生成的代码在_pb2.py文件中合成,而 gRPC-specific 代码在_pb2_grpc.py文件中。后者的 python 模块导入前者。

    示例

    syntax = "proto3";
    package route_guide_simple;
    
    // the route guide service
    service RouteGuide{
        // A simple RPC 
        rpc GetFeature (Point) returns (Feature) {}
    }
    
    message Point{
        int32 latitude = 1;
        int32 longitude = 2;
    }
    
    message Feature{
        string name = 1;
        Point location = 2;
    }
    

    当服务被编译时,gRPC 的protoc 插件会生成类似于下面的 _pb2_grpc.py 文件的代码:

    # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
    """Client and server classes corresponding to protobuf-defined services."""
    import grpc
    
    import route_guide_pb2 as route__guide__pb2
    
    class RouteGuideStub(object):
        """the route guide service
        """
    
        def __init__(self, channel):
            """Constructor.
    
            Args:
                channel: A grpc.Channel.
            """
            self.GetFeature = channel.unary_unary(
                    '/route_guide_simple.RouteGuide/GetFeature',
                    request_serializer=route__guide__pb2.Point.SerializeToString,
                    response_deserializer=route__guide__pb2.Feature.FromString,
                    )
    
    class RouteGuideServicer(object):
        """the route guide service
        """
    
        def GetFeature(self, request, context):
            """A simple RPC 
            """
            context.set_code(grpc.StatusCode.UNIMPLEMENTED)
            context.set_details('Method not implemented!')
            raise NotImplementedError('Method not implemented!')
    
    def add_RouteGuideServicer_to_server(servicer, server):
        rpc_method_handlers = {
                'GetFeature': grpc.unary_unary_rpc_method_handler(
                        servicer.GetFeature,
                        request_deserializer=route__guide__pb2.Point.FromString,
                        response_serializer=route__guide__pb2.Feature.SerializeToString,
                ),
        }
        generic_handler = grpc.method_handlers_generic_handler(
                'route_guide_simple.RouteGuide', rpc_method_handlers)
        server.add_generic_rpc_handlers((generic_handler,))
    
     # This class is part of an EXPERIMENTAL API.
    class RouteGuide(object):
        """the route guide service
        """
    
        @staticmethod
        def GetFeature(request,
                target,
                options=(),
                channel_credentials=None,
                call_credentials=None,
                insecure=False,
                compression=None,
                wait_for_ready=None,
                timeout=None,
                metadata=None):
            return grpc.experimental.unary_unary(request, target, '/route_guide_simple.RouteGuide/GetFeature',
                route__guide__pb2.Point.SerializeToString,
                route__guide__pb2.Feature.FromString,
                options, channel_credentials,
                insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
    

    Code Elements

    gRPC 生成的代码首先导入 grpc 包和由 protoc 合成的纯 _pb2 模块,后者定义了非 gRPC 特定的代码元素,比如对应于协议缓冲消息的类和反射使用的描述符。

    对于.proto 文件中的每个服务 Foo,会生成三个主要元素:

    • Stub:RouteGuideStub被客户端用于连接gRpc服务
    • Servicer:RouteGuideServicer被服务端用于实现gRpc服务
    • Registration Function: add_RouteGuideServicer_to_server函数用于向grpc. Server对象注册服务者。

    Stub

    生成的 Stub 类由 gRPC 客户端使用。它具有一个构造函数,它使用grpc. Channel对象并初始化存根。对于服务中的每个方法,初始化器向具有相同名称的存根对象添加对应的属性。根据RPC类型(一元或流式),该属性的值将是UnaryUnaryMultiCallable,UnaryStreamMultiCallable,StreamUnaryMultiCallable或StreamStreamMultiCallable类型的可调用对象。

    Servicer

    对于每个服务,将生成一个 Servicer 类,作为服务实现的超类。对于服务中的每个方法,将在 Servicer 类中生成对应的函数。使用服务实现重写此函数。.proto 文件中注释与代码元素相关联,在生成的 python 代码中以 docstring 的形式出现。

    Registration Function

    对于每个服务,都会生成一个函数,该函数在grpc. Server对象上注册一个实现该服务的Servicer对象,以便服务器可以将查询路由到相应的服务器。这个函数接受一个实现 Servicer 的对象,通常是上面描述的生成的 Servicer 代码元素的一个子类的实例,以及一个 grpc. Server 对象。

    相关文章

      网友评论

          本文标题:一个简单的python gRpc (route_guide_si

          本文链接:https://www.haomeiwen.com/subject/phpqdltx.html