brpc组件bvar源码解析(四)Sampler、SamplerCollector和Window类簇

2023-11-02

1.Sampler类

Sampler是所有采样类的基类。采样类中最重要的是take_sample函数,采样类的schedule函数调用之后,它的take_sample函数将会被一个专门的线程每1秒定时调用。

Sampler类的定义:
在这里插入图片描述

Sampler是一个纯虚类,take_sample是纯虚函数需要子类实现。

Sampler继承自LinkNode,即拥有了previous_和next_指针,可以作为双向链表的节点。

Sampler有两个成员变量,一个是_used表示当前采样类是否生效;一个是_mutex保护_used。

构造函数、析构函数和destroy函数

默认_used设为true。

如果采样类不再使用,则调用其destroy函数,设置_used为false,实现延迟删除,至于从哪里删除,后面会讲到。
在这里插入图片描述

schedule函数:

在这里插入图片描述
注册当前采样类的地址到全局单例SamplerCollector中,后面讲到SamplerCollector时再详细介绍内部实现。

2.Sample类

定义:
在这里插入图片描述
这个类很简单,保存了bvar的类型T的值data,和时间time_us。它用于保存一次采样的结果和采样时的时间。

3.SamplerCollector类

定义:
在这里插入图片描述
上面的注释可以帮助理解为什么SamplerCollector要设计成继承自Reducer。正常情况我们一般的实现是这样,用一个容器C保存所有注册的采样类和一个mutex M保护,设置定时线程来定期采样。但是这个性能不好,每次开始采样前都要用M加锁保护,以至于创建Window<>(创建Window<>是会创建sampler类、并注册到SamplerCollector中)需要等锁释放。如果想让创建Window<>的开销可以忽略不计,还需要更好的方案。

这里就提供了一个更好的方案,就是继承自Reducer<Sampler*, CombineSampler>。这样SamplerCollector就是一个bvar,保存的是Sampler*,累加器是CombineSampler,看一下CombineSampler的实现:
在这里插入图片描述

前面说了Sampler*是可以作为双向链表的节点的。CombineSampler的两个参数是2个双向链表,它的操作就是把两个双向链表连接起来。

综合上面的信息,SamplerCollector继承自Reducer<Sampler*, CombineSampler>之后,调用operator<<函数可以轻易的添加Sampler到stl数据中,这个过程是没有锁的,就解决了前面说的问题:想让创建Window<>的开销可以忽略不计;调用get_value函数可以通过累加器CombineSampler将所有的Sampler组成一个双向链表。

成员变量

在这里插入图片描述
_created:是否创建了采样线程
_stop:是否需要退出采样线程中的循环
_cumulated_time_us:采样线程中遍历所有的Sampler*进行采样花费的时间的总和
_tid:采样线程id

函数create_sampling_thread

SamplerCollector类的构造函数中就调用了函数create_sampling_thread。
实现:
在这里插入图片描述

(1)创建采样线程执行函数sampling_thread
(2)如果采样线程创建成功,则通过pthread_atfork注册当fork子进程时在子进程上下文中fork函数返回之前调用child_callback_atfork函数
A)child_callback_atfork函数中创建全局SamplerCollector单例,并调用其after_forked_as_child函数
B)after_forked_as_child中重置_created为false,并调用create_sampling_thread以实现在子进程中创建采样线程。

采样线程执行run函数

采样线程首先调用的函数sampling_thread,它的实现很简单就是调用SamplerCollector::run函数:
在这里插入图片描述

所以看run函数:
在这里插入图片描述
1.获得所有的Sampler
1)调用SamplerCollector::reset函数,Reducer::reset函数中执行了_combiner.reset_all_agents,通过前文知道它把所有stl保存的Sampler*连接成一个双向链表s返回,原来的保存的地方重置为null。
2)reset函数返回的双向链表s和root连接到一起。即root是之前就已经获得的所有的Sampler构造的双向链表,s是最新加入的Sampler构造的双向链表。
2.遍历所有的Sampler
1)遍历root中的所有Sampler,判断是否被destroy(_used字段),如果是,则从root中删除、并delete,否则进行2)
2)调用Sampler::take_sample进行采样操作,take_sample是Sampler具体子类实现的
3.sleep
1)如果上述全过程花费的时间不超过1s,则sleep多余的时间
2)如果花费超过1s,则consecutive_nosleep+1,consecutive_nosleep超过WARN_NOSLEEP_THRESHOLD(默认值2)时打印log

4.ReducerSampler类

ReducerSampler是Sampler类的子类,定义如下:
在这里插入图片描述
继承自Sampler,有4个模板参数:
R:一般就是Reducer类或Reducer子类
T、Op、InvOp:Reducer类的三个模板参数

成员变量:
在这里插入图片描述
_reducer:保存传入的R类型对象指针
_window_size:窗口大小
_q:保存所有Sample的有界队列(即循环队列);当容量全部有值、再加入新增时将替换最早加入的值。

构造函数

在这里插入图片描述
初始化_reducer,设置_window_size为1;调用take_sample。

函数take_sample

函数是具体的采样操作。
在这里插入图片描述
1._q容量不足_window_size,则扩容量
2.获得_reducer最新值
1)如果没有反向op,例如Maxer、Miner,则获得当前的最新值返回、并重置原保存的值
2)如果有反向op,例如Adder,则获得当前的最新值返回即可,之后需要窗口内的值时可以通过反向op操作来得到
3)无论有没有反向op都可以通过1)来实现,但是对于有反向op的,用2)效率会更高
3.加入到_q中
1)保存当前时间(采样时间)到time_us
2)采样结果Sample保存到_q中

函数get_value

在这里插入图片描述
1.获得窗口前后的采样值
1)最新采样的值保存到latest
2)从现在往过去数第window_size个采样结果保存到oldest;如果全部采样结果就不足window_size个,则保存最老的采样结果到oldest
3)上述两个值作为窗口前后的采样值
2.根据上述值计算窗口内的值
1)如果没有反向op,那么就老老实实地从oldest依次到latest,依次执行op操作(op例如取最大值)
2)如果有反向op,那么就可以根据inv_op、oldest、latest快速计算得到(例如对于Adder,latest - oldest就是窗口类的值)
3)oldest、latest采样时间间隔保存到result->time_us

使用ReducerSampler的地方

ReducerSampler中有如下定义:
typedef detail::ReducerSampler<Reducer, T, Op, InvOp> sampler_type;

在Reducer::get_sampler首次被调用时将创建ReducerSampler对象(传入this指针)、并加入到全局单例SamplerCollector中:
在这里插入图片描述

那么Reducer::get_sampler什么时候被调用呢,下面的Window<>创建的时候。下面会介绍到。

5.WindowBase类

定义:
在这里插入图片描述
模板参数:
R:具体的bvar类型
SeriesFrequency:和SeriesSampler有关,我们这次不介绍这个。

成员变量:
在这里插入图片描述
_var:指针指向具体的bvar的对象
_window_size:窗口大小;根据前面我们知道,窗口是指采样点的窗口,虽然采样线程是每1s采样一次,但由于要遍历所有的Sampler的take_sample,所以对于每个Sampler而言不一定是每1s采样一次
_sampler:属于bvar对象_var的采样对象,弱引用
_series_sampler:我们这次不介绍SeriesSampler相关的。

构造函数

在这里插入图片描述

WindowBase类的构造函数需要传2个内容:bvar对象的指针和窗口大小。
_sampler赋值bvar对象的sampler指针,这里是弱引用,并修改_sampler的窗口大小。

get_span函数

在这里插入图片描述
获得指定窗口大小的Sample对象值。

get_value函数

在这里插入图片描述

调用get_span获得指定窗口大小的Sample对象值,然后返回Sample.data,即具体的bvar存储的类型的值。

6.WindowBase子类

1.Window类继承自WindowBase,比较简单,不赘述
2.PerSecond类也继承自WindowBase,特别的,它override了get_value函数:
在这里插入图片描述
它在获得了Sample.data之后,又除了一下窗口首末真正的采样时间间隔,正如类名一样表示每秒的采样值。

7.最后

其他的一些类,例如LatencyRecorder(时延),PassiveStatus(get_value时调用指定函数对象获得value)都比较简单,就不赘述了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

brpc组件bvar源码解析(四)Sampler、SamplerCollector和Window类簇 的相关文章

  • BASIC 中的 C 语言中的 PeekInt、PokeInt、Peek、Poke 等效项

    我想知道该命令的等效项是什么Peek and Poke 基本和其他变体 用 C 语言 类似PeekInt PokeInt 整数 涉及内存条的东西 我知道在 C 语言中有很多方法可以做到这一点 我正在尝试将基本程序移植到 C 语言 这只是使用
  • C# 异步等待澄清?

    我读了here http blog stephencleary com 2012 02 async and await html that 等待检查等待的看看它是否有already完全的 如果 可等待已经完成 那么该方法将继续 运行 同步
  • 随着时间的推移,添加到 List 变得非常慢

    我正在解析一个大约有 1000 行的 html 表 我从一个字符串中添加 10 个字符串 td 每行到一个list td
  • 如何在 C++ 中标记字符串?

    Java有一个方便的分割方法 String str The quick brown fox String results str split 在 C 中是否有一种简单的方法可以做到这一点 The 增强分词器 http www boost o
  • 无限循环与无限递归。两者都是未定义的吗?

    无副作用的无限循环是未定义的行为 看here https coliru stacked crooked com view id 24e0a58778f67cd4举个例子参考参数 https en cppreference com w cpp
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • WcfSvcHost 的跨域异常

    对于另一个跨域问题 我深表歉意 我一整天都在与这个问题作斗争 现在已经到了沸腾的地步 我有一个 Silverlight 应用程序项目 SLApp1 一个用于托管 Silverlight SLApp1 Web 的 Web 项目和 WCF 项目
  • 两个类可以使用 C++ 互相查看吗?

    所以我有一个 A 类 我想在其中调用一些 B 类函数 所以我包括 b h 但是 在 B 类中 我想调用 A 类函数 如果我包含 a h 它最终会陷入无限循环 对吗 我能做什么呢 仅将成员函数声明放在头文件 h 中 并将成员函数定义放在实现文
  • 实例化类时重写虚拟方法

    我有一个带有一些虚函数的类 让我们假设这是其中之一 public class AClassWhatever protected virtual string DoAThingToAString string inputString retu
  • C 编程:带有数组的函数

    我正在尝试编写一个函数 该函数查找行为 4 列为 4 的二维数组中的最大值 其中二维数组填充有用户输入 我知道我的主要错误是函数中的数组 但我不确定它是什么 如果有人能够找到我出错的地方而不是编写新代码 我将不胜感激 除非我刚去南方 我的尝
  • C# 动态/expando 对象的深度/嵌套/递归合并

    我需要在 C 中 合并 2 个动态对象 我在 stackexchange 上找到的所有内容仅涵盖非递归合并 但我正在寻找能够进行递归或深度合并的东西 非常类似于jQuery 的 extend obj1 obj2 http api jquer
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 有没有办法让 doxygen 自动处理未记录的 C 代码?

    通常它会忽略未记录的 C 文件 但我想测试 Callgraph 功能 例如 您知道在不更改 C 文件的情况下解决此问题的方法吗 设置变量EXTRACT ALL YES在你的 Doxyfile 中
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • C++ 中的 include 和 using 命名空间

    用于使用cout 我需要指定两者 include
  • C# 中最小化字符串长度

    我想减少字符串的长度 喜欢 这串 string foo Lorem ipsum dolor sit amet consectetur adipiscing elit Aenean in vehicula nulla Phasellus li
  • Mono 应用程序在非阻塞套接字发送时冻结

    我在 debian 9 上的 mono 下运行一个服务器应用程序 大约有 1000 2000 个客户端连接 并且应用程序经常冻结 CPU 使用率达到 100 我执行 kill QUIT pid 来获取线程堆栈转储 但它总是卡在这个位置
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐

  • centos7中iptables配置log日志记录所有流量

    CentOS 7 0默认使用的是firewall作为防火墙 使用iptables必须重新设置一下 1 直接关闭防火墙 systemctl stop firewalld service 停止firewall systemctl disable
  • c语言编译器mingw的使用说明,C语言编译器MINGW的使用说明

    在mingw环境中生成和使用dll都是十分方便的 1 生成dll gcc g shared o test dll test c 一直用VS 看现在Eclipse很火 便想弄一下玩玩 用到了MINGW 继而用到了GCC 对GCC相当的不熟悉
  • [JS] Flatten array

    拍平数组 这个在lodash里也是很常见的方法 那自己实现一个看看 普通拍平 const flatten arr gt concat arr map v gt Array isArray v v v 测试 flatten 1 2 3 4 5
  • 【历史上的今天】1 月 16 日:互联网工程任务组(IETF)成立;AMD 收购 NexGen;eBay 的第一位员工出生

    整理 王启隆 透过 历史上的今天 从过去看未来 从现在亦可以改变未来 今天是 2022 年 1 月 16 日 在 25 年前的今天 国家电力公司组建成立 电力是运作着我们生活的基本 国家电力公司成立于 1997 年 1 月 16 日 于 2
  • Text-To-Speech(TTS)语音朗读

    Text To Speech TTS 语音朗读 更新 2010 04 08 来源 互联网 字体 大 中 小 TextToSpeech简称 TTS 是Android 1 6版本中比较重要的新功能 将所指定的文本转成不同语言音频输出 它可以方便
  • 微软消息队列-MicroSoft Message Queue(MSMQ)队列的C#使用

    什么是MSMQ Message Queuing MSMQ 是微软开发的消息中间件 可应用于程序内部或程序之间的异步通信 主要的机制是 消息的发送者把自己想要发送的信息放入一个容器中 我们称之为Message 然后把它保存至一个系统公用空间的
  • 大一上期Python考前复习

    初识Python考试前复习 Python介绍 基本语法 1 赋值语句 2 del语句 3 if 语句 4 for循环语句 4 while循环语句 4 1循环下的语句 数据类型 1 数据可变性 2 数据类型 2 1 格式化输出 3 列表 字典
  • 初阶C语言(1)-6200字带你初识C语言

    目录 前言 如何创建一个项目 第一个C语言程序 基本数据类型 变量与常量 字符串与转义字符 选择语句 循环语句 函数 数组 操作符 关键字 常量和宏 指针 结构体 前言 本节旨在初步认识C语言 有的知识在之后会详细讲 C语言是一门面向过程的
  • Java+SSM+Vue 毕业设计 房屋出租出售管理系统(含源码+论文)

    文章目录 1 项目简介 2 实现效果 2 1 界面展示 3 设计方案 3 1 概述 3 2 系统流程 3 2 1 系统开发流程 3 2 2 操作流程 3 3 系统结构设计 4 项目获取 1 项目简介 Hi 各位同学好呀 这里是M学姐 今天向
  • STL之lexicographical_compare

    lexicographical compare and lexicographical compare 3way the latter is not part of the C standard 功能 Returns true if the
  • pip豆瓣源

    豆瓣源地址 https pypi douban com simple 使用方法 pip install 需要的包名 i https pypi douban com simple 豆瓣源也解决了我使用清华源或阿里源的时候Anaconda下载的
  • 字符数组学习

    有关办公中内容读取和写入的 是很常见的 需要通过移位和偏移 计算每次的地址 再累加运算 一种是字符数组 另一种是字符串常量 它们在内存中的存储位置不同 字符数组可以读取和修改 而字符串常量只能读取不能修改 比如这样字符串 NOVO4CCC6
  • 网络5层体系结构中的数据传输过程

    5层网络体系结构 应用层 运输层 网络层 网际层 数据链路层 物理层 物理层 主要任务 考虑怎样才能在连接各种计算的传输媒体上传输数据比特流 数据链路层 mac层 主要任务 在同一个局域网中 分组怎样从一个主机传送到另一个主机 不经过路由器
  • Java 介绍与环境搭建

    文章目录 Java 介绍与环境搭建 Java 背景介绍 Java 背景故事 Java 三大平台 Java SE Java ME Java EE Java 跨平台工作原理 平台与跨平台 跨平台工作原理 JDK 下载和安装 下载 JDK 安装
  • 【imx6ull】视频监控项目(usb摄像头+ffmepeg)

    文章目录 前言 1 总体方案介绍 2 配置v4l2驱动与UVC驱动 3 v4l2应用编程测试摄像头 4 ffmepg移植 总结 前言 参考视频 韦东山老师手把手带你从0开始自己做一个视频监控系统 1 总体方案介绍 这篇文章写的很好 很容易理
  • cmake——project

    命令project用于设置项目的名称 project
  • 关于VISIO工具栏、菜单栏消失的解决办法

    关于VISIO工具栏 菜单栏消失的解决办法 1 打开注册表编辑器 2 VISIO 2000 HKEY CURRENT USER Software Visio Visio2000 Toolbars 删除上述键值 再启动VISIO 2000就可
  • 查看占用指定端口的程序

    netstat lntup grep 8080
  • 【半监督学习】5、Efficient Teacher

    文章目录 一 背景 二 方法 2 1 Dense Detector 2 2 Pseudo Label Assigner 2 3 Epoch Adaptor 三 效果 论文 Efficient Teacher Semi Supervised
  • brpc组件bvar源码解析(四)Sampler、SamplerCollector和Window类簇

    1 Sampler类 Sampler是所有采样类的基类 采样类中最重要的是take sample函数 采样类的schedule函数调用之后 它的take sample函数将会被一个专门的线程每1秒定时调用 Sampler类的定义 Sampl