netty和dubbo的hashwheel时间轮定时器原理和源码解析
时间轮定时器
时间轮定时器的论文ppt参考:论文ppt:http://www.cse.wustl.edu/~cdgill/courses/cs6874/TimingWheels.ppt
hash时间轮结构
基本过程跟时钟类似,秒针每间隔一段时间跳一格,跳到哪格就遍历该格中存储的任务列表判断每个的任务是否到了时间。涉及的两个重要概念:
1.Tick Duration
时间轮跳动的时间间隔,默认是100ms,不是精确的时间。
2.Ticks per Wheel (Wheel Size)
时间轮的格数默认是 512.
时间轮处理过程
理解时间轮的工作原理需要理解这几个过程:
时间指针的跳动
指针跳动对应到时间轮上桶的位置
桶内部如何增加移除任务
桶内部任务如何进行超时判断
任务需要等待多少圈数及圈数的维护
Worker & WorkerThread
时间轮的核心逻辑都在workerThread的Worker中执行, 创建timer时创建worker线程执行worker任务,死循环。包括:
- 时间指针的跳动
- waitForNextTick
- 指针跳动对应到时间轮上桶的位置
- int stopIndex = (int) (ticks & mask);
- 任务需要等待多少圈数及圈数的维护
1.
private final class Worker implements Runnable {private final Set<Timeout> unprocessedTimeouts = new HashSet<Timeout>();private long tick;@Overridepublic void run() {// Initialize the startTime.startTime = System.nanoTime();if (startTime == 0) {// We use 0 as an indicator for the uninitialized value here, so make sure it's not 0 when initialized.startTime = 1;}// Notify the other threads waiting for the initialization at start().startTimeInitialized.countDown();do {//计算下次跳动的起始时间,为当前桶任务最大的截止时间final long deadline = waitForNextTick();if (deadline > 0) {int idx = (int) (tick & mask);processCancelledTasks();HashedWheelBucket bucket =wheel[idx];transferTimeoutsToBuckets();bucket.expireTimeouts(deadline);tick++;}} while (WORKER_STATE_UPDATER.get(HashedWheelTimer.this) == WORKER_STATE_STARTED);//timer被stop了// Fill the unprocessedTimeouts so we can return them from stop() method.for (HashedWheelBucket bucket: wheel) {bucket.clearTimeouts(unprocessedTimeouts);}for (;;) {HashedWheelTimeout timeout = timeouts.poll();if (timeout == null) {break;}if (!timeout.isCancelled()) {unprocessedTimeouts.add(timeout);}}processCancelledTasks();}//从timeouts队列添加到时间轮的桶中,定位到桶,然后插入到链表private void transferTimeoutsToBuckets() {// transfer only max. 100000 timeouts per tick to prevent a thread to stale the workerThread when it just// adds new timeouts in a loop.for (int i = 0; i < 100000; i++) {HashedWheelTimeout timeout = timeouts.poll();if (timeout == null) {// all processedbreak;}if (timeout.state() == HashedWheelTimeout.ST_CANCELLED) {// Was cancelled in the meantime.continue;}//根据超时时间计算需要经过多少轮过期long calculated = timeout.deadline / tickDuration;timeout.remainingRounds = (calculated - tick) / wheel.length;final long ticks = Math.max(calculated, tick); // Ensure we don't schedule for past.//定位到桶的index,ticks mod 时间轮桶个数 mask=buckets.size-1int stopIndex = (int) (ticks & mask);HashedWheelBucket bucket = wheel[stopIndex];bucket.addTimeout(timeout);}}private void processCancelledTasks() {for (;;) {HashedWheelTimeout timeout = cancelledTimeouts.poll();if (timeout == null) {// all processedbreak;}try {timeout.remove();} catch (Throwable t) {if (logger.isWarnEnabled()) {logger.warn("An exception was thrown while process a cancellation task", t);}}}}/*** calculate goal nanoTime from startTime and current tick number,* then wait until that goal has been reached.* @return Long.MIN_VALUE if received a shutdown request,* current time otherwise (with Long.MIN_VALUE changed by +1)等待下次跳动指针的时间,时间间隔*/private long waitForNextTick() {// 计算下次跳动的时间,为当前桶任务最大的截止时间long deadline = tickDuration * (tick + 1);for (;;) {final long currentTime = System.nanoTime() - startTime;// (deadline-currenttime)ms + 1mslong sleepTimeMs = (deadline - currentTime + 999999) / 1000000;//到时间了返回,tick+1if (sleepTimeMs <= 0) {if (currentTime == Long.MIN_VALUE) {return -Long.MAX_VALUE;} else {//curenttime>=deadlinereturn currentTime;}}// Check if we run on windows, as if thats the case we will need// to round the sleepTime as workaround for a bug that only affect// the JVM if it runs on windows.//// See https://github.com/netty/netty/issues/356if (PlatformDependent.isWindows()) {sleepTimeMs = sleepTimeMs / 10 * 10;}try {//没到时间睡眠一会Thread.sleep(sleepTimeMs);} catch (InterruptedException ignored) {if (WORKER_STATE_UPDATER.get(HashedWheelTimer.this) == WORKER_STATE_SHUTDOWN) {return Long.MIN_VALUE;}}}}public Set<Timeout> unprocessedTimeouts() {return Collections.unmodifiableSet(unprocessedTimeouts);}}
HashedWheelBucket && Timeout
Timeout是任务的抽象,bucket是任务的容器。
HashedWheelBucket 类似链表,保存每个刻度的任务,expireTimeouts方法移除过期任务列表
- 桶内部如何增加移除任务
- 桶内部任务如何进行超时判断操作
- 任务的轮数维护也在这里处理
两个过程在桶内部实现,见expireTimeouts代码
public void expireTimeouts(long deadline) {HashedWheelTimeout timeout = head;// process all timeoutswhile (timeout != null) {HashedWheelTimeout next = timeout.next;//如果任务是到期的任务,直接移除,remaininrounds指任务还需要等几轮才到期if (timeout.remainingRounds <= 0) {next = remove(timeout);if (timeout.deadline <= deadline) {timeout.expire();} else {// The timeout was placed into a wrong slot. This should never happen.throw new IllegalStateException(String.format("timeout.deadline (%d) > deadline (%d)", timeout.deadline, deadline));}} else if (timeout.isCancelled()) {next = remove(timeout);} else {//每轮经过一轮,等待轮数减1timeout.remainingRounds --;}timeout = next;}
}
netty和dubbo的hashwheel时间轮定时器原理和源码解析相关推荐
- Dubbo原理和源码解析之服务引用
github新增仓库 "dubbo-read"(点此查看),集合所有<Dubbo原理和源码解析>系列文章,后续将继续补充该系列,同时将针对Dubbo所做的功能扩展也进行 ...
- 打印当前时间 毫秒_时间轮定时器
时间轮算法(Timing-Wheel)很早出现在linux kernel 2.6中.因效率非常高,很多应用框架都实现了这个算法.还有些定时器使用最小堆实现,但总体来说,时间轮算法在插入性能上更高. 前 ...
- 分级时间轮优化普通时间轮定时器(2):滴答式分层计时轮
<实现较低的计时器粒度以重传TCP(RTO):时间轮算法如何减少开销> <分级时间轮优化普通时间轮定时器> Table of Contents 描述 新闻 用法 执照 资源 其 ...
- java方法里面能改定时器的时间吗_Kafka 时间轮的原理和实现
女主宣言 Kafka 作为一个支持实时处理大量请求的分布式流处理平台,需要一个设计良好的定时器来处理异步任务.本文作者将基于 Kafka 1.1.0 版本的源码来介绍 Kafka 中定时器的基础数据结 ...
- 单片机定时器之改良版:时间轮定时器
前段时间把自己以前用的单片机定时器整理出来,我称之为简单定时器,这种简单定时器比较适合定时器使用量少的程序中,如果定时器数量要求多,精度要求高,效率就会有问题,为此,俺就实现了一个时间轮定时器,简单测 ...
- java实现时间轮定时器_c++ 时间轮定时器实现
前言 之所以写这篇文章,是在一篇博客中看到了时间轮定时器这个东西,感觉很是惊艳,https://www.cnblogs.com/zhongwencool/p/timing_wheel.html.在以前 ...
- 时间轮python_算法 数据结构——时间轮定时器
时间轮定时器 优点:可保证每次执行定时器任务都是O(1)复杂度,在定时器任务密集的情况下,性能优势非常明显. 缺点:内存占用较大,当定时器使用不频繁,处理时间跨度很大的时候,效率低下. C++实现: ...
- linux编程之经典多级时间轮定时器(C语言版)
一. 多级时间轮实现框架 上图是5个时间轮级联的效果图.中间的大轮是工作轮,只有在它上的任务才会被执行:其他轮上的任务时间到后迁移到下一级轮上,他们最终都会迁移到工作轮上而被调度执行. 多级时间轮的原 ...
- HashedWheelTimer时间轮定时任务原理分析
一.示例代码 HashedWheelTimer时间轮是一个高性能,低消耗的数据结构,它适合用非准实时,延迟的短平快任务,例如心跳检测. 时间轮是一种非常惊艳的数据结构.其在Linux内核中使用广泛,是 ...
- Kafka 时间轮的原理和实现
女主宣言 Kafka 作为一个支持实时处理大量请求的分布式流处理平台,需要一个设计良好的定时器来处理异步任务.本文作者将基于 Kafka 1.1.0 版本的源码来介绍 Kafka 中定时器的基础数据结 ...
最新文章
- Ubuntu 系统安装.deb安装包
- 故障申报系统php源码,运维不再专业救火 不会PHP照样找出代码性能问题
- PHP中使用include、require、include_once、require_once的区别
- dotweb——go语言的一个微型web框架(二)启动dotweb
- linux虚拟机网络查看的方式
- sqlserver获得到当前游标中存在的数据行数
- 初学大数据之Pycharm常用的快捷键总结
- js反混淆还原工具_SATURN反混淆框架
- OC--Protocol 协议
- 中国非制式爆炸物薄膜传感器研究取得进展
- 【三维路径规划】基于matlab A_star算法无人机三维路径规划【含Matlab源码 003期】
- 内置函数的数据聚合NumpyPandas
- 创客思维在高等教育中的启迪作用
- Spring data Mongo $map转写用例
- [回溯法] 和尚挑水问题-华为笔试
- linux 775和777权限有什么区别
- 安全知识图谱 | 绘制软件供应链知识图谱,强化风险分析
- 足球数据采集 php,世上最权威足球数据网站只爱梅西?
- 【t100】汤姆斯的天堂梦
- Amazon Advantage 可通过EDI实现哪些业务单据对接?
热门文章
- C语言选择题(含答案)
- 计算机网络自动分配ip地址,计算机ip地址设置 自动获取IP和静态IP
- 通达信版弘历软件指标_背离王 通达信副图源码 为弘历软件破释公式
- 一周之内连过5人,HCIE-RS新版实验这么好考?
- libcrypto yum 安装_CentOS升级OpenSSL至OpenSSL 1.1.0f版本其中有遇到libcrypto.so的问题...
- 微信H5页面自定义微信分享内容
- 【前端第七课】媒体查询的语法;移动端适配相关知识点;Grid高级布局
- 西北工业大学noj数据结构实验003稀疏矩阵转置
- vue json对象转数组_vue的数据驱动原理及简单实现
- 06 OPENMV中的AT指令集操作