异步C ++客户端中关于CompletionQueue的困惑 [英] Confusion around CompletionQueue in an async C++ client

查看:619
本文介绍了异步C ++客户端中关于CompletionQueue的困惑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对如何将CompletionQueue用于异步C ++客户端感到有些困惑.我的服务器是C#,所以这里的问题纯粹是客户端以异步方式向服务器发送请求.

I have some confusion with regards on how to use CompletionQueue for async C++ client. My server is in C#, so my question here is purely around the client sending a request in an async manner to the server.

作为参考,这是我设置客户端代码以发出异步请求的方式:

For reference, here is how I setup my client code to make an async request:

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的最佳方法. 此答案似乎暗示可以在请求中使用单个CompletionQueue.如果多个线程使用同一队列发出请求,这将如何表现.假设我将上面的代码更改为使用共享队列,而不是为每个请求创建一个新队列.

My first confusion is around the best way to setup the CompletionQueue. This answer seems to suggest that a single CompletionQueue can be used across requests. How will this behave if multiple threads use the same queue to make requests. Let's say that I change my code above to use a shared queue rather than creating a fresh one per request.

  • 一个线程如何知道它收到的响应是针对它的,而不是针对另一个线程的?

  • How will one thread know that the response it receives is intended for it, rather than for a different thread?

我是否需要为每个线程分配一个唯一的标记,并在每个线程上检查从队列接收的标记是否与我最初发送的标记匹配?

Do I need to assign a unique tag per thread, and on each thread check that the received tag from the queue matches the one I originally sent?

如果线程A收到了用于线程B的标签,这是否意味着线程B以后可以查询其标签,还是该标签丢失了,因为线程A首先看到了它?

If thread A receives a tag intended for thread B, does that mean thread B will be able to query for its tag later, or is that tag lost because thread A saw it first?

实际上是否存在每个请求使用新队列而不是共享的主要问题?

Is there actually a major issue of using a fresh queue per request, rather than sharing?

我的第二个困惑是关于grpc::CompletionQueue::NextStatus::SHUTDOWN结果.如果我对每个请求使用一个新的队列,而没有在队列上显式调用shutdown,是否有可能发生这种结果?如果是,将触发什么?我执行的一项测试是在请求进行过程中关闭服务器,但是我没有得到关机结果,而是得到了状态为UNAVAILABLEgrpc::CompletionQueue::NextStatus::GOT_EVENT结果.

My second confusion is around grpc::CompletionQueue::NextStatus::SHUTDOWN result. If I use a fresh queue per request, and not explicitly call shutdown on the queue, is this result ever likely to occur? If yes, what will trigger it? One test I carried out is closing the server while a request is in progress, however rather than getting the shutdown result I got the grpc::CompletionQueue::NextStatus::GOT_EVENT result, with status set as UNAVAILABLE.

我最后的困惑是围绕ok标志.我已经阅读了此答案,但是仍然不清楚.给定上面发布的用例和代码,如果我从队列中得到的结果是grpc::CompletionQueue::NextStatus::GOT_EVENT,则ok标志可以为false,如果是,那么将导致它为false?同样,这完全是围绕客户端,而不是服务器上CompletionQueue的处理方式.

My final confusion is around the ok flag. I have read this answer, however it's still not very clear. Given the use case and code posted above, if the result I get from the queue is grpc::CompletionQueue::NextStatus::GOT_EVENT, can the ok flag be false, and if yes, what will cause it to be false? Again this is purely around the client and not how CompletionQueue is handles on the server.

推荐答案

  1. 使用从完成队列返回的标签来了解哪个完成队列操作启动了此操作.您必须确保使用同一标签的同时没有进行两个CQ操作.
  2. 每个飞行中的CQ操作同时需要一个不同的标签.无论这些操作是从同一线程还是从不同线程启动的,都适用.
  3. 每个标签仅从Next函数中出现一次.如果您有多个线程在同一个CompletionQueue上调用Next,则它们都应该能够处理(或传递)注册到该CQ的任何标签.
  4. 您可以为每个RPC使用一个新队列,就像sync API实际上在内部一样.那样效率较低,并且在这种情况下基本上会转移到sync API,因为您将无法同时进行许多未完成的操作.

您需要在某个时候调用Shutdown,然后清空队列.这是API的标准.否则,尤其是对于服务器CQ,可能会发生泄漏.通过消耗,我的意思是调用Next直到返回false(或调用AsyncNext直到返回SHUTDOWN).

You need to call Shutdown at some point and then drain the queue. That's the standard for the API. Otherwise, especially for server CQs, there will likely be leaks. By drain, I mean call Next until it returns false (or AsyncNext until it returns SHUTDOWN).

ok可以为false.如果仅查看客户端一元调用(如您的示例),则不会为false.错误的ok本质上意味着RPC的这一面已损坏.有关此文档的信息位于CQ的头文件中.

ok can be false for GOT_EVENT for streaming calls, server-side calls, etc. If you're only looking at client unary calls (like your example), it won't be false. A false ok essentially means that this side of the RPC is broken. The documentation for this is in the header file for the CQ.

这篇关于异步C ++客户端中关于CompletionQueue的困惑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆