我正在制作一个节俭服务,并通过Thrift在C ++中的TNonBlockingServer
选项设置了一个事件驱动的服务器。但是我现在的服务取决于其他服务,我想知道在进行只有同步接口的RPC调用时最佳做法是什么。
假设服务A依赖于服务U和V,并且当服务A从U和V获得RPC调用的结果时,它使用分别来自U和V的先前调用的结果对服务X和Y进行RPC调用。 ,但thrift只提供同步客户端调用,即没有选项使客户端调用异步和基于事件(如服务器代码所示)。所以代码大纲看起来有点像这个
Output some_RPC_call(Input input) {
auto u_result = U(input);
auto x_result = X(u_result);
auto v_result = V(input);
auto y_result = Y(v_result);
return Output(x_result, y_result);
}
正如您所看到的,对服务U,V,X和Y的调用都是同步和阻塞的,因此这里浪费了大量时间,并且每个服务器请求(即some_RPC_call()
)的延迟都高于如果服务发出异步请求(大概是)
此问题的一个解决方案是按如下方式构造上述请求
Output some_RPC_call(Input input) {
auto future_x_result = std::async([&]() {
auto u_result = U(input);
return X(u_result);
});
auto future_y_result = std::async([&]() {
auto v_result = V(input);
return Y(v_result);
});
return Output(future_x_result.get(), future_y_result.get());
}
这样两个请求都在自己的线程中进行服务,因此两者都没有阻塞另一个。但是std::async
具有与手动创建线程对象并等待它完成相同的开销,因为默认启动策略只是在单独的线程上启动任务。
通常的方法是使用线程池和消息队列来单独调度每个thrift客户端请求吗?但是,其中的并行性仅限于池提供的线程粒度(例如,在大多数情况下,线程池中的线程数等于系统上的处理器数,并且每当一个I / O请求阻塞时,同样处理器块上排队的其他I / O请求)。
我很难找到一个可以在这里正常工作的解决方案,因为很难将上述请求转换为事件驱动系统,其中每个请求仅在其依赖的套接字准备好时才在消息队列上提供接收或发送价值。
有关如何解决此问题的任何建议?节俭有本机解决方案吗?