2021SC@SDUSC BRPC代码分析(二) —— bvar-reducer类及其子类详解

2021SC@SDUSC


一、reducer类简介

        Reducer用二元运算符把多个值合并为一个值,运算符需满足结合律,交换律,没有副作用。只有满足这三点,我们才能确保合并的结果不受线程私有数据如何分布的影响。像减法就不满足结合律和交换律,它无法作为此处的运算符。
        reducer << e1 << e2 << e3的作用等价于reducer = e1 op e2 op e3。常见的Redcuer子类有bvar::Adder, bvar::Maxer, bvar::Miner。(op指operator,操作符)
        结合律:a Op (b Op c) == (a Op b) Op c;
        交换律:a Op b == b Op a;
        没有副作用:a Op b在a和b固定的条件下永远不会改变。

二、代码分析

先看一下Reducer类的属性,Reducer类继承自上篇博客讲解的Variable类,所以默认是拥有上文介绍的全部属性及方法的。我们再来看额外增加的属性。首先说明下三个template模板类。分别是存储的数据类型T;Reducer的运算符Op;还有Op的逆向操作符InvOp,默认是VoidOp,也就是没有逆向操作符。InvOp在定时采样的时候会用到,本篇文章暂不涉及,后面解析采样相关内容的时候再详细说明。这三个参数主要参与构造了AgentCombiner、ReducerSampler两个类,这些类在后续都会被详细介绍,在此处我们只会在分析本篇代码时简述所需要的它的功能。
同时还有继承了Sampler的SeriesSampler内部改写并实现了部分方法,SeriesSampler将Variable采样的值存成序列,内部Series分配60+60+24+30大小的空间,用于存储秒、分、时和天的采样值,这些聚合值是性能监控最在意的点,极大提高了程序的可观察性。将性能数据聚合工作放在运行时做,用很小的开销实现即时观察功能。这些后续也会详细分析。
在这里插入图片描述
还有一部分私有属性。SeriesSampler和sampler_type因为不是必须的也可能不只是一个,所以是指针类型,而combiner_type和InvOp则是需要直接初始化的变量,之所以只有invop是因为可以看到上面的combiner_type里面会保存Op和T,不需要重复保存。
在这里插入图片描述
了解了属性后,我们来看一下构造和析构函数。
构造函数可以看到在初始化构造时,两个sampler并没有被赋值。需要时可以追加。
析构函数中,因为Reducer类继承自Variable,所以析构时先调用variable的hide函数,然后如果两个sampler存在,调用各自的destroy()函数将其销毁。
在这里插入图片描述
接下来开始分析方法,reducer类主要的作用就是读写值。
每个继承Reducer类的都将重载<<运算符,reducer << e1 << e2 << e3的作用等价于reducer = e1 op e2 op e3,可以理解为追加值。<<结果返回Reducer类自身的引用。
在这里插入图片描述
这个重载<<函数里。首先是调用combiner的get_or_create_tls_agent函数取到当前线程的agent,内部实现上就是tls(thread local stroage)的相关操作(后续会分析),如果还未分配则会新建agent,得到agent之后调用agent的modify()函数用操作符op和追加值value进行修改操作。
在这里插入图片描述

然后是读取值,主要就是通过combiner聚合各个agent的值,上面的CHECK函数第二个条件没有采样不能调用是比较好理解的,没有sampler自然无处调用此函数。第一个条件是如果当前Reducer已被window跟踪定时采样并且不存在InvOp是不能调用这个函数的,比如下面会提到的Maxer和Miner。因为线程存储的关系,对于这类没有InvOp的Reducer,在定时采样(take_sample)的时候需要reset agent,调用这个函数取不到正确值。
在这里插入图片描述
在这里插入图片描述
介绍完Reducer类,介绍brpc内置的几个常用的Reducer子类,比如bvar::Adder, bvar::Maxer, bvar::Miner。
给出一个实例应用。
bvar::Adder<int> sum;
sum << 1 << 2 << 3 << 4;
LOG(INFO) << sum.get_value(); -->10
编写一个Reducer子类,首先定义自己的操作符Op和逆向操作符InvOp(如果有的话),对于bvar::Adder,Op即为加法(理解上应该当做+=)
,MinusFrom逆操作即为-=。在这里插入图片描述
Adder类的代码如下,可以看到继承了Reducer类,传入了数据类型T和上述的两个操作符,Adder的构造函数直接将其作为bvar“曝光”,调用了上篇博客提到过的expose,析构则直接调用hide()将其“隐藏”。(explicit关键字的作用就是防止类构造函数的隐式自动转换,这个关键词之间没有见过,学到了)
在这里插入图片描述
其他两个子类和Adder类基本完全相同,不再赘述。但有一点需要注意,与Adder类不同的是,不论是Maxer还是Miner,都需要在初始化时“预定”一个值,不然就没办法进行初次的比较了。比如下面的Miner,在构造时就预设了std::numeric_limits<T>::max()这一T类型最大值(注意T如果是自定义类型,则需要专门化 std::numeric_limits<>和重载 operator<,当然也可以直接给定自己的最大值),这样在<<追加进第一个数val时,保证当前结果是val自身。
在这里插入图片描述


总结

以上就是今天介绍的全部内容,本文进行了bvar内reducer类及其子类的功能说明和详细源码分析,之后的博客会继续进行代码的分析。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值