官方文档:
https://grpc.io/docs/languages/
https://grpc.io/docs/languages/python/
通道复用案例
一、hello.proto
文件内容
syntax = "proto3";
package hello;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
二、gRPC工具编译
python -m grpc_tools.protoc -I./ --python_out=. --grpc_python_out=. ./hello.proto
生成了两个文件:
hello_pb2.py
此文件包含生成的 request(HelloRequest
) 和 response(HelloReply
) 类。hello_pb2_grpc.py
此文件包含生成的 客户端(GreeterStub
)和服务端(GreeterServicer
)的类。
三、greeter_server.py
文件内容
from concurrent import futures
import time
import grpc
import hello_pb2
import hello_pb2_grpc
_ONE_DAY_IN_SECONDS = 60 * 60 * 24
class Greeter(hello_pb2_grpc.GreeterServicer):
# 工做函数
def SayHello(self, request, context):
return hello_pb2.HelloReply(message='Hello, %s!' % request.name)
def serve():
# gRPC 服务器
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
hello_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:50051')
server.start() # start() 不会阻塞,若是运行时你的代码没有其它的事情可作,你可能须要循环等待。
try:
while True:
time.sleep(_ONE_DAY_IN_SECONDS)
except KeyboardInterrupt:
server.stop(0)
if __name__ == '__main__':
serve()
四、greeter_client.py
文件内容
import grpc
import hello_pb2
import hello_pb2_grpc
def run():
# 创建一个通道ch1
ch1 = grpc.insecure_channel('localhost:50051')
# 检测通道ch1是否就绪,在这里会创建一个tcp连接
grpc.channel_ready_future(ch1).result(timeout=10)
# 创建一个通道ch2
ch2 = grpc.insecure_channel('localhost:50051')
# 检测通道ch2是否就绪,在这里并不会创建一个新的tcp连接,而是会复用前面的连接
grpc.channel_ready_future(ch2).result(10)
stub1 = hello_pb2_grpc.GreeterStub(ch1)
# 如果没有channel_ready_future,则在这里创建tcp连接
response = stub1.SayHello(hello_pb2.HelloRequest(name='goodspeed'))
print("Greeter client received: " + response.message)
stub2 = hello_pb2_grpc.GreeterStub(ch2)
# 使用的还是第一个连接
response = stub2.SayHello(hello_pb2.HelloRequest(name='goodspeed2'))
print("Greeter client received: " + response.message)
if __name__ == '__main__':
run()
这段代码会复用连接。
如果是windows,使用netstat命令观察到只建立了一个连接:
netstat -an|find "50051"
如果是linux,使用netstat命令观察到只建立了一个连接:
netstat -an|grep ESTABLISHED | grep 50051
通道不复用案例
有时候在做性能测试、压测的时候需要关闭这个特性。
如果是在多线程或者多进程里面,通道不会被复用。
参考到官方文档,有一个参数可以进行控制。
使用参数grpc.use_local_subchannel_pool
进行控制。
https://grpc.github.io/grpc/python/grpc.html#grpc.insecure_channel
/** If set, uses a local subchannel pool within the channel. Otherwise, uses the
* global subchannel pool. */
#define GRPC_ARG_USE_LOCAL_SUBCHANNEL_POOL "grpc.use_local_subchannel_pool"
greeter_client.py
代码如下:
import grpc
import hello_pb2
import hello_pb2_grpc
def run():
opts = [
("grpc.use_local_subchannel_pool", 1),
]
# 创建一个通道ch1
ch1 = grpc.insecure_channel('localhost:50051',opts)
# 检测通道ch1是否就绪,在这里会创建一个tcp连接
grpc.channel_ready_future(ch1).result(timeout=10)
# 创建一个通道ch2
ch2 = grpc.insecure_channel('localhost:50051',opts)
# 检测通道ch2是否就绪,在这里会创建一个tcp连接,不会复用前面的连接
grpc.channel_ready_future(ch2).result(10)
stub1 = hello_pb2_grpc.GreeterStub(ch1)
# 如果没有channel_ready_future,则在这里创建tcp连接
response = stub1.SayHello(hello_pb2.HelloRequest(name='goodspeed'))
print("Greeter client received: " + response.message)
stub2 = hello_pb2_grpc.GreeterStub(ch2)
# 如果没有channel_ready_future,则在这里创建tcp连接
response = stub2.SayHello(hello_pb2.HelloRequest(name='goodspeed2'))
print("Greeter client received: " + response.message)
if __name__ == '__main__':
run()
这段代码不会复用连接。
如果是windows,使用netstat命令观察到建立了2个连接:
netstat -an|find "50051"
如果是linux,使用netstat命令观察到建立了2个连接:
netstat -an|grep ESTABLISHED | grep 50051