gRPC Python线程池 vs 最大并发RPC数

14
启动Python的grpc.server时,maximum_concurrent_rpcs和线程池中使用的max_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,
)

请问您能否确认我是否回答了您的问题。是的,我知道您早些时候就提出了这个问题。只是为了追求声望分数 :) - Attila123
1个回答

19

如果您的服务器已经同时处理了 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):

正如预期的那样,前两个客户端的请求处理立即开始(可以在服务器输出中看到),因为有大量可用线程,但第三个客户端立即被拒绝(如预期)并显示StatusCode.RESOURCE_EXHAUSTEDConcurrent RPC limit exceeded!

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

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

我再次大致同时运行了我的三个客户端。

结果是,第一个客户端立即得到服务。第二个需要等待10秒钟(当第一个被服务时),然后才得到服务。第三个客户端立即被拒绝。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接