如何正确异步使用grpc(ClientAsyncReaderWriter)

Posted

技术标签:

【中文标题】如何正确异步使用grpc(ClientAsyncReaderWriter)【英文标题】:How to correctly use grpc asynchronously (ClientAsyncReaderWriter) 【发布时间】:2017-10-16 09:46:51 【问题描述】:

我找不到展示如何使用 ClientAsyncReaderWriter 的 grpc 示例(有吗?)。我自己尝试了一些东西,但是在引用计数方面遇到了麻烦。我的问题来自跟踪代码。

struct grpc_call 有一个 gpr_refcount 类型的成员,称为 ext_ref。 ClientContext C++ 对象包装了 grpc_call,并将其保存在成员 grpc_call *call_; 中。只有 ext_ref 为 0 时,才能删除这个 grpc_call 指针。

当我与ClientReader同步使用grpc时:

在其实现中,它使用 CreateCall() 和 PerformOps() 添加到 ext_ref (ext_ref == 2)。 然后我使用 Pluck() 从 ext_ref 中减去 (ext_ref == 1)。 最后使用~ClientContext()从ext_ref中减去,这样ext_ref == 0就删除了调用

但是当我与ClientAsyncReaderWriter异步使用grpc时:

首先使用 asyncXXX(),此 API 使用 CreateCall() 并注册 Write() (ext_ref == 2)。 然后它使用 AsyncNext() 来获取标签...必须使用写入或读取操作符。 所以ext_ref > 1 永远,除非 got_event 你不处理。

我这样称呼它:

struct Notice

    std::unique_ptr<
        grpc::ClientAsyncReaderWriter<ObserveNoticRequest, EventNotice>
    >                          _rw;
    ClientContext              _context;
    EventNotice                _rsp;

注册线程

CompletionQueue *cq = new CompletionQueue;
Notice *notice = new Notice;
notice->rw = stub->AsyncobserverNotice(&context, cq, notice); 

// here context.call_.ext_ref is 2

获取 CompletionQueue 事件线程

void *tag = NULL;
bool ok = false;
CompletionQueue::NextStatus got = CompletionQueue::NextStatus::TIMEOUT;
gpr_timespec deadline;
deadline.clock_type = GPR_TIMESPAN;
deadline.tv_sec = 0;
deadline.tv_nsec = 10000000;

got = cq->AsyncNext<gpr_timespec>(&tag, &ok, deadline);

if (GOT_EVENT == got) 
    if (tag != NULL) 
        Notice *notice = (Notice *)tag;
        notice->_rw->Read(&_rsp, notice);

        // here context.call_.ext_ref is 2.
        // now I want to stop this CompletionQueue. 

        delete notice;

        // use ~ClientContext(), ext_ref change to 1
        // but only ext_ref == 0, call_ be deleted
    

【问题讨论】:

谢谢回复,我已经更新代码了 有一个asynchronous example here。如果没有真正深入了解您所询问的具体内容,您是否觉得您所面临的问题存在于该示例中?你所做的有什么不同? 感谢您一直以来对我的关注。但我不喜欢这个问题。我编译示例,发现它使用类 ClientAsyncResponseReader,当使用 AsyncSayHello 注册调用时,关键是 ClientAsyncResponseReader 使用 SneakyCallOpSet 进行初始化。比使用 Next() ,它调用 FinalizeResult() 并返回 false。所以 UNREF ext_ref 操作两次。但我使用 ClientAsyncReaderWriter 传输流 grpc。这一切都使用CallOpSet。那你能告诉我如何使用客户端 AsyncReadWrite 吗? 我只是想帮助你,虽然我知道 C++,但我对此一无所知。看起来您正在查看一个详细的问题并且有(英语)语言障碍,并且您是 *** 的新用户,所以我想给您对这里的人的积极印象。但也许要做的事情是继续编辑,直到您确定您表达了误解,并要求开发人员来这里做出回应。 *** 是一个很好的网站,但只有遵循协议才能为您提供帮助。 非常感谢您的慷慨帮助。谢谢你给了这么多建议。我想知道如何使用 ClientAsyncReaderWriter。 【参考方案1】:

看看这个文件,client_async.cc,很好地使用 ClientAsyncReaderWriter。如果您仍然有困惑,请创建一个非常清晰的问题重现,我们将进一步调查。

【讨论】:

以上是关于如何正确异步使用grpc(ClientAsyncReaderWriter)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用异步 GRPC 调用有效地管理内存

grpc-java:正确处理客户端重试以进行服务流调用

gRPC 异步服务死锁/永远卡住

gRPC:在 C++ 中关闭异步服务器的推荐方法是啥?

如何使用 grpc-web 构建 react-redux 应用程序?

如何将 JWT 与 grpc 一起使用?