gRPC Python thread_pool 对比 max_concurrent_rpcs

gRPC Python thread_pool vs max_concurrent_rpcs

启动Pythongrpc.server时,线程池中使用的maximum_concurrent_rpcsmax_workers有什么区别。如果我想要maximum_concurrent_rpcs=1,是否还要提供多线程给线程池?

换句话说,我应该将 maximum_concurrent_rpcs 匹配到我的 max_workers,还是应该提供比最大并发 RPC 数更多的工作人员?

server = grpc.server(
    thread_pool=futures.ThreadPoolExecutor(max_workers=1),
    maximum_concurrent_rpcs=1,
)

如果您的服务器已经在同时处理 maximum_concurrent_rpcs 个请求,并且收到另一个请求,该请求将立即被拒绝。

如果 ThreadPoolExecutor 的 max_workers 小于 maximum_concurrent_rpcs 那么在所有线程都忙于处理请求后,下一个请求将排队,并在线程完成处理后进行处理。

我也有同样的问题。为了回答这个问题,我调试了一下 maximum_concurrent_rpcs 会发生什么。调试在我的 virtualenv 中进行到 py36/lib/python3.6/site-packages/grpc/_server.py。搜索 concurrency_exceeded。底线是,如果服务器已经在处理 maximum_concurrent_rpcs 并且另一个请求到达,它将被拒绝:

# ...
elif concurrency_exceeded:
    return _reject_rpc(rpc_event, cygrpc.StatusCode.resource_exhausted,
                        b'Concurrent RPC limit exceeded!'), None
# ...

我用 gRPC Python 快速入门示例进行了尝试:

greeter_server.py我修改了SayHello()方法:

# ...
def SayHello(self, request, context):
    print("Request arrived, sleeping a bit...")
    time.sleep(10)
    return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
# ...

serve()方法:

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10), maximum_concurrent_rpcs=2)
    # ...

然后我打开了 3 个终端并在其中手动执行客户端(尽可能快地使用 python greeter_client.py:

正如预期的那样,对于前 2 个客户端,请求的处理立即开始(可以在服务器的输出中看到),因为有足够的线程可用,但第 3 个客户端立即被拒绝(如预期的那样) StatusCode.RESOURCE_EXHAUSTED, Concurrent RPC limit exceeded!.

现在测试当没有足够的线程分配给 ThreadPoolExecutor 时会发生什么,我将 max_workers 修改为 1:

server = grpc.server(futures.ThreadPoolExecutor(max_workers=1), maximum_concurrent_rpcs=2)

我 运行 我的 3 个客户大约在与以前相同的时间再次出现。

结果是第一个立即得到服务。第二个需要等待 10 秒(当第一个被送达时)然后它被送达。第三个直接被拒