Python gRPC

Google gRPC(Google Remote Procedure Call)是一个高性能、开源的远程过程调用框架,它允许客户端直接调用远程服务器上的方法,就像调用本地方法一样,屏蔽了网络通信的复杂性。

1. 配置安装

在正式编写代码之前,我们需要先完成开发环境的搭建与依赖包的安装。执行下面代码创建一个单独的虚拟环境,并安装 Python GRPC 需要的包。

# 创建虚拟环境
conda create -n grpc-env python=3.10

# 安装 gRPC 相关包
pip install grpcio grpcio-tools
  • grpcio 用于运行 gRPC 客户端和服务端
  • grpcio-tools 用于编译 .proto 文件

安装之后,我们创建一个 demo.proto 的 gRPC 服务定义文件,内容如下:

syntax = "proto3";

service Greeter
{
  rpc sayHello (Request) returns (Response) {}
}

message Request
{
  string name = 1;
  int32 age = 2;
}

message Response
{
  string message = 1;
}
  • service Greeter:定义了一个服务,包含一个 sayHello 方法
  • Request/Response:定义了请求和响应的数据结构

接下来,在命令行中输入以下命令编译 proto 文件:

python -m grpc_tools.protoc -I. --python_out=pyi_out:. --grpc_python_out=. demo.proto

此时,会根据 proto 文件生成两个 py 文件:

  • demo_pb2.py 对 message 进行操作的封装
  • demo_pb2.pyi 用于提供静态类型信息提示
  • demo_pb2_grpc.py 对 service 进行操作的封装

2. 远程调用

我们将接下来分别编写服务端与客户端的代码,实现一个完整的 gRPC 通信流程。

2.1 服务端

import grpc
from demo_pb2_grpc import GreeterServicer
from demo_pb2_grpc import add_GreeterServicer_to_server
from demo_pb2 import Request, Response
from concurrent import futures


# 实现服务接口
class MyGreeterServicer(GreeterServicer):
    # request 表示客户端的请求参数对象
    # context 表示一次客户端请求的上下文信息
    def sayHello(self, request : Request, context : grpc.ServicerContext):
        print('客户端:', context.peer())

        for key, value in context.invocation_metadata():
            print('元信息:', key, value)

        print('请求参数:', request.name, request.age)
        print('-' * 50)

        # 当执行这一行代码时,终止后续调用并返回错误
        context.abort(code=grpc.StatusCode.NOT_FOUND, details='出错了')
        return Response(info='ok')


def run_server():
    # 创建服务对象
    # thread_pool: 用于执行 RPC 调用的线程池。服务端接收到请求后,会从线程池中分配线程来处理 handler 中的逻辑。
    server = grpc.server(thread_pool=futures.ThreadPoolExecutor(max_workers=10))
    # 设置服务端口
    server.add_insecure_port('0.0.0.0:50052')
    # 注册服务接口
    add_GreeterServicer_to_server(MyGreeterServicer(), server)
    # 开启服务
    server.start()
    server.wait_for_termination()


if __name__ == '__main__':
    run_server()

2.2 客户端

import grpc
from demo_pb2 import Request, Response
from demo_pb2_grpc import GreeterStub


def demo():
    channel = grpc.insecure_channel('127.0.0.1:50052')
    stub = GreeterStub(channel)

    # 构造请求元信息
    metadata = (('token', 'abc123'), ('trace_id', 'trace-xyz-789'))
    # 构造请求参数信息
    request = Request(name='obama', age=20)

    response : Response = stub.sayHello(request, metadata=metadata)
    print('远程调用结果:', response.info)


if __name__ == '__main__':
    demo()
未经允许不得转载:一亩三分地 » Python gRPC
评论 (0)

6 + 3 =