流程


环境准备
1
| pip3 install grpcio grpcio-tools
|
定义服务
使用protocolbuffers/protobuf格式来创建结构化数据文件SimpleCal.proto
,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| syntax = "proto3";
service Cal { rpc Add(AddRequest) returns (ResultReply) {} rpc Multiply(MultiplyRequest) returns (ResultReply) {} }
message AddRequest { int32 number1 = 1; int32 number2 = 2; }
message MultiplyRequest { int32 number1 = 1; int32 number2 = 2; }
message ResultReply { int32 number = 1; }
|
- 在
SimpleCal.proto
文件中定义了一个服务Cal
,定义了2个RPC方法:Add
和Multiply
,需要分别在gRPC的服务端中实现加法和乘法。
- 同时我们也定义了2个方法的参数,
Add
方法的参数是AddRequest
,包含number1和number2两个整数参数。 Multiply
方法的参数是MultiplyRequest
,里面也有number1和number2两个整数参数。两个函数的返回结构都是ResultReply
,内容是一个整数。
message
是代表数据结构(里面可以包括不同类型的成员变量,包括字符串、数字、数组、字典……),service
代表 RPC 接口。变量后面的数字是代表进行二进制编码时候的提示信息,1~15 表示热变量,会用较少的字节来编码。
根据上面的定义,生成Python代码:
1 2 3
| $ python3 -m grpc_tools.protoc -I. --python_out=. --grpc_python_out=. ./SimpleCal.proto $ ls SimpleCal_pb2_grpc.py SimpleCal_pb2.py SimpleCal.proto
|
- 使用
python3 -m grpc_tools.protoc --hel
能获得命令的参数含义。
ls
可以看到grpc_tools
帮我们自动生成了 SimpleCal_pb2_grpc.py
, SimpleCal_pb2.py
这2个文件。这2个文件会在后面的客户端和服务端代码中被引用。
服务端和客户端样例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| from concurrent import futures import grpc import SimpleCal_pb2 import SimpleCal_pb2_grpc
class CalServicer(SimpleCal_pb2_grpc.CalServicer): def Add(self, request, context): print("Add function called") return SimpleCal_pb2.ResultReply(number=request.number1 + request.number2)
def Multiply(self, request, context): print("Multiply service called") return SimpleCal_pb2.ResultReply(number=request.number1 * request.number2)
def serve(): server = grpc.server(futures.ThreadPoolExecutor(max_workers=5)) SimpleCal_pb2_grpc.add_CalServicer_to_server(CalServicer(),server) server.add_insecure_port("[::]:50051") server.start() print("grpc server start...") server.wait_for_termination()
if __name__ == '__main__': serve()
|
- 这里的重点在于
CalServicer
类中对Add
和Multiply
两个方法的实现。
- 逻辑很简单,从
request
中读取number1和number2,然后相加。注意,这里的所有变量都需要完整名称:request.number1和request.number2, 不能使用位置参数。Multiply
的实现和Add
一样,不多说了。
-
serve
函数里定义了gRPC的运行方式,使用5个worker的线程池。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import SimpleCal_pb2 import SimpleCal_pb2_grpc import grpc
def run(n, m): channel = grpc.insecure_channel('localhost:50051') stub = SimpleCal_pb2_grpc.CalStub(channel) response = stub.Add(SimpleCal_pb2.AddRequest(number1=n, number2=m)) print(f"{n} + {m} = {response.number}") response = stub.Multiply(SimpleCal_pb2.MultiplyRequest(number1=n, number2=m)) print(f"{n} * {m} = {response.number}")
if __name__ == "__main__": run(100, 300)
|
客户端的逻辑更加简单,就连上gRPC服务,然后发起调用。
下面开启服务端,并执行客户端代码调用gRPC服务,结果如下:
1 2 3 4
| $ python3 cal_server.py & $ python3 cal_client.py 100 + 300 = 400 100 * 300 = 30000
|