博客
关于我
定时器的实现
阅读量:730 次
发布时间:2019-03-21

本文共 2188 字,大约阅读时间需要 7 分钟。

定时器设计概述

1. 定时器概述

定时器是服务端应用程序中负责执行时间相关任务的核心组件。服务端逻辑主要由两个事件驱动:网络事件和时间事件。不同框架对这两种事件的处理方式有所不同。

在单线程模型中(如 Nginx、Redis 等),网络事件和时间事件通过同一线程同步处理;而在多线程模型中(如 Skynet 等),则分别由不同的线程处理网络事件和时间事件。

1.1 单线程定时器实现

while (!quit) {    int now = get_now_time(); // 单位:ms    int timeout = get_nearest_timer() - now;    if (timeout < 0) timeout = 0;    int nevent = epoll_wait(epfd, ev, nev, timeout); // 利用 epoll_wait 实现定时器    for (int i = 0; i < nevent; i++) {        // 处理网络事件    }}

1.2 多线程定时器实现

void* thread_timer(void* thread_param) {    init_timer();    while (!quit) {        update_timer(); // 更新定时器检测        sleep(t); // sleep 时间 t    }    clear_timer();    return NULL;}pthread_create(&pid, NULL, thread_timer, &thread_param);

2. 定时器设计

2.1 接轴设计

// 初始化定时器void init_timer();// 添加定时器cbNode* add_timer(int expire, callback cb);// 删除定时器bool del_timer(Node* node);// 找到最近要触发的定时任务Node* find_nearest_timer();// 更新定时器检测void update_timer();

2.2 数据结构选择

时间轮需要高效的数据结构支持,主要有以下四种选择:

2.2.1 红黑树

红黑树可以支持 O(logN) 增、删、查操作。 дополнитель有序树结构允许快速查找最小节点,但需要维护节点的有序性。

2.2.2 最小堆

最小堆以完全二叉树形式存在,支持 O(logN) 增、查操作,删除操作通过辅助数据结构加速。堆的最小节点总是根节点。

2.2.3 跳表

跳表的增、删、查操作复杂度为 O(logN),但其空间复杂度较高。虽然最小节点查找时间复杂度为 O(1),但大数据量下不具备高效性。

2.2.4 时间轮

时间轮可以在 O(1) 时间复杂度下完成增、删、查操作,最小节点查找也为 O(1)。适合多个定时任务同时触发的情况。

2.3 红黑树实现定时器

void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) {    ngx_rbtree_node_t **p;    for ( ;; ) {        p = ((ngx_rbtree_key_int_t)(node->key - temp->key) < 0) ? &temp->left : &temp->right;        if (*p == sentinel) {            break;        }        temp = *p;    }    *p = node;    node->parent = temp;    node->left = sentinel;    node->right = sentinel;    ngx_rbt_red(node);}

2.4 最小堆实现定时器

最小堆的增操作需要满足完全二叉树定义,加入新节点后可能需要上浮操作。删除操作需要借由上升或下沉来维护堆的结构。

2.5 时间轮实现定时器

int seconds[60]; // 表盘刻度描述int tick = 0;// 时间轮每秒移动一次while (!quit) {    tick = (tick + 1) % 60; // 秒针循环}

3. 时间轮应用实例

3.1 单层级时间轮

用于解决心跳检测中常见的时延问题。例如,客户端每5秒发送心跳包,服务端若10秒内未收到心跳包则清除连接。

单层级时间轮设计

  • 准备一个固定大小的数组存储连接数据。
  • 每秒检查一次心跳包发送情况。
  • 使用指针移动数组位置,实现心跳检测。
  • 多层级时间轮设计

    通过将定时任务按优先级分层,实现多级时间轮共享机制。例如,紧急任务放在第一层,普通任务放在第二层等。

    3.2 时间轮优化建议

  • 合理设置数组长度,考虑连接数量和心跳检测时间。
  • 优化指针移动方式,避免重复计算。
  • 维护使用计数器,确保心跳检测逻辑正确。
  • 通过以上设计,可以编写高效、灵活的定时器系统,满足不同场景的服务端需求。

    转载地址:http://xjngz.baihongyu.com/

    你可能感兴趣的文章
    Luogu2973:[USACO10HOL]赶小猪
    查看>>
    mabatis 中出现&lt; 以及&gt; 代表什么意思?
    查看>>
    Mac book pro打开docker出现The data couldn’t be read because it is missing
    查看>>
    MAC M1大数据0-1成神篇-25 hadoop高可用搭建
    查看>>
    mac mysql 进程_Mac平台下启动MySQL到完全终止MySQL----终端八步走
    查看>>
    Mac OS 12.0.1 如何安装柯美287打印机驱动,刷卡打印
    查看>>
    MangoDB4.0版本的安装与配置
    查看>>
    Manjaro 24.1 “Xahea” 发布!具有 KDE Plasma 6.1.5、GNOME 46 和最新的内核增强功能
    查看>>
    mapping文件目录生成修改
    查看>>
    MapReduce程序依赖的jar包
    查看>>
    mariadb multi-source replication(mariadb多主复制)
    查看>>
    MariaDB的简单使用
    查看>>
    MaterialForm对tab页进行隐藏
    查看>>
    Member var and Static var.
    查看>>
    memcached高速缓存学习笔记001---memcached介绍和安装以及基本使用
    查看>>
    memcached高速缓存学习笔记003---利用JAVA程序操作memcached crud操作
    查看>>
    Memcached:Node.js 高性能缓存解决方案
    查看>>
    memcache、redis原理对比
    查看>>
    memset初始化高维数组为-1/0
    查看>>
    Metasploit CGI网关接口渗透测试实战
    查看>>