grpc之AsyncNext:获取完全队列中的请求/响应

举报
想飞的咸鱼 发表于 2023/07/16 10:47:10 2023/07/16
【摘要】 gRPC之AsyncNext方法的用法介绍

        grpc异步传输,请求,应答都依赖于完全队列CompletionQueue(客户端),ServerCompletionQueue(服务器);客户端,服务器使用Next/AsyncNext方法获取响应,如下:

void * tag - nullptr;
bool ok = false;
CompletionQueue cq;

if(cq.Next(&tag, &ok))
{
    //逻辑实现
    //客户端处理回应
    //服务器处理请求    
}

        如上代码,Next,AsyncNext如果由响应返回true。下面详细介绍下这两个函数:

Next

        获取队列中可用的请求/响应,如果没有可用的数据则程序阻塞,直到获取到可用数据。

bool Next(void** tag, bool* ok)
/*
描述:
    获取队列中可用的请求/响应
参数:
    tag: 请求/响应的对象指针
    ok: rcp的连接状态,连接异常返回false
*/

AsyncNext

        获取队列中可用的请求/响应,如果没有可用的数据则阻塞一定时间然后返回,这个阻塞的时间就是设置的超时时间。

template <typename T>
NextStatus AsyncNext(void** tag, bool* ok, const T& deadline)
/*
描述:
    获取队列中可用的请求/响应
参数:
    tag: 请求/响应的对象指针
    ok: rcp的连接状态,连接异常返回false
    deadline:超时
*/

用法

        Next的用法不多做解释,参考概要中的示例,下面着重介绍下AsyncNext的用法,个人认为AsyncNext比Next更加好用;废话不多说直接上代码方便理解:

void thread_pro(void)
{
    void *got_tag;
    bool ok = false;
    int i = 0;
    //设置超时时间
    gpr_timespec deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(1000, GPR_TIMESPAN));
    // while (cq_.Next(&got_tag, &ok))
    while (cq_.AsyncNext(&got_tag, &ok, deadline))
    {
        InterfaceAsyncClientCall *call = static_cast<InterfaceAsyncClientCall *>(got_tag);
        if (call != nullptr)
        {
            if (!ok)
            {
                got_tag = nullptr;
                ok = false;
                deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(1000, GPR_TIMESPAN));
                continue;
                call->status = Status::OK; // 事件异常断开,强行终止。
            }
            call->Proceed();
        }
        got_tag = nullptr;
        ok = false;
        //更新超时时间的时间值
        deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(1000, GPR_TIMESPAN));
    }
}

        该代码是我实际项目中用到的,着重说以超时机制,该机制和我们的普遍的认知还是有点区别的:

设置超时时间

gpr_timespec deadline = gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(1000, GPR_TIMESPAN));

gpr_time_add:将两个时间值相加,某时刻的时间值+时间间隔,第一个参数是时间值,第二个参数是时间间隔。

gpr_now(GPR_CLOCK_REALTIME):获取当前时间;

gpr_time_from_millis(1000, GPR_TIMESPAN):设置时间间隔为1s。

假设时间值为2023-07-13:00:00:00, 时间间隔为1s,则返回值deadline的值为2023-07-13:00:00:01

所以这行代码:

while (cq_.AsyncNext(&got_tag, &ok, deadline))

        如果完全队列没有响应,则AsyncNext方法阻塞到2023-07-13:00:00:01时刻进行返回,所以AsyncNext方法的超时是以某时刻为准,下次循环当前时间已经超过deadline的时间值从而没有超时效果;

        所以如果想要实现每次循环都阻塞1s需要在每次循环结束之前重新更新超时时间的时间值,示例代码的27行就起到更新作用。

值得注意的一点是:

got_tag = nullptr;

ok = false;

        这两个局部变量也要实时更新,因为got_tag,ok变量在while外部定义,但是在队列中没有请求/响应的时候got_tag的状态不会改变,举个例子:

        程序运行后还没有任何请求,则got_tag为nullptr,这个很正常表示队列中没有数据,假如来了一个请求/响应,got_tag为请求/响应的对象的指针;但是如果之后没有请求/响应(队列中没有可用数据)got_tag仍然指向上一个请求对象的地址。这就导致没有请求也会进入if (call != nullptr)容错中。

        因此我一般会在每次循环结束就将got_tag的状态重新指向nullptr,方便以后的判断和操作。

        想要了解更多grcp的技术用法及音视频相关技术请参考我的主页博客获取更多,或者持续关注我的作品。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。