【发布时间】:2020-03-08 12:47:41
【问题描述】:
对于如何将CompletionQueue 用于异步 C++ 客户端,我有些困惑。我的服务器是 C#,所以我的问题完全是关于客户端以异步方式向服务器发送请求。
作为参考,以下是我设置客户端代码以发出异步请求的方式:
template<typename ResponseType, typename AsyncOpExecutor>
bool DoAsyncOp(const AsyncOpExecutor& op, const unsigned int deadlineMs, ResponseType& response)
{
grpc::ClientContext ctx;
grpc::CompletionQueue queue;
const std::unique_ptr<grpc::ClientAsyncResponseReaderInterface<ResponseType>> asyncOpResponse = op(ctx, queue);
grpc::Status status;
int requestTag = 1;
asyncOpResponse->Finish(&response, &status, (void*)requestTag);
bool result = false;
bool gotEvent = false;
do
{
const std::chrono::time_point<std::chrono::system_clock> deadline = std::chrono::system_clock::now() + std::chrono::milliseconds(deadlineMs);
void* got_tag;
bool ok = false;
const grpc::CompletionQueue::NextStatus nextStatus = queue.AsyncNext(&got_tag, &ok, deadline);
switch (nextStatus)
{
case grpc::CompletionQueue::NextStatus::TIMEOUT:
continue;
case grpc::CompletionQueue::NextStatus::GOT_EVENT:
assert(got_tag == (void*)requestTag);
// ok is always true even if I close the server while request is in progress.
assert(ok);
result = status.ok();
gotEvent = true;
break;
// Given that I am creating a new CompletionQueue per request (not using a shared one), is this flag likely to occur?
case grpc::CompletionQueue::NextStatus::SHUTDOWN:
result = false;
gotEvent = false;
break;
default:
result = false;
gotEvent = false;
break;
}
} while (!gotEvent);
return result;
}
我的第一个困惑是设置CompletionQueue 的最佳方式。 This answer 似乎暗示可以跨请求使用单个 CompletionQueue。如果多个线程使用同一个队列发出请求,这将如何表现。假设我将上面的代码更改为使用共享队列,而不是为每个请求创建一个新队列。
一个线程如何知道它收到的响应是给它的,而不是给另一个线程的?
我是否需要为每个线程分配一个唯一标签,并在每个线程上检查从队列中接收到的标签是否与我最初发送的标签匹配?
-
如果线程 A 收到一个用于线程 B 的标签,这是否意味着线程 B 以后可以查询它的标签,还是因为线程 A 先看到它而导致该标签丢失?
李> 每个请求使用新队列而不是共享实际上存在一个主要问题吗?
我的第二个困惑是grpc::CompletionQueue::NextStatus::SHUTDOWN 结果。如果我对每个请求使用一个新队列,并且没有在队列上显式调用shutdown,那么这个结果是否可能发生?如果是,什么会触发它?我执行的一项测试是在请求进行时关闭服务器,但是我得到了grpc::CompletionQueue::NextStatus::GOT_EVENT 结果,状态设置为UNAVAILABLE,而不是得到关闭结果。
我最后的困惑在于ok 标志。我已经阅读了this answer,但是仍然不是很清楚。鉴于上面发布的用例和代码,如果我从队列中得到的结果是grpc::CompletionQueue::NextStatus::GOT_EVENT,ok 标志是否可以为假,如果是,什么会导致它为假?同样,这纯粹是围绕客户端,而不是 CompletionQueue 在服务器上的处理方式。
【问题讨论】:
标签: grpc