游戏服务器架构:基于匿名函数的高性能异步定时器系统

作者:码客(ygluu 卢益贵) 关键词:游戏服务器架构、匿名函数、高性能、异步定时器。

一、前言

本文主要介绍适用于MMO/RPG游戏服务端的、基于匿名函数做定时器回调函数的、高性能异步触发的定时器系统的设计方案,以解决常规线程loop-run-check模式的弊端。本文使用伪代码简明阐述理论。

二、系统框图

如图所示,本方案四大亮点:

1、Main-Thread一直Wait-Msg(堵塞模式),抛弃了常规的线程loop-run-check模式,避免了无意义的Run、Sleep、业务Obj众多时的桶轮询机制,最大的发挥线程性能。

2、Timer-Thread仅根据interval来检查和触发,同一个interval的多个定时器只触发一次事件入列(第④步)。这样当定时器数量达到百万级的时候,第④步产生的消息队列数量非常少(因为游戏场景下的interval数值范围是有限的),减少了高频触发导致的线程锁和线程唤醒的性能消耗。

3、兼顾成员函数指针和匿名函数形式的定时器回调函数,开发更加简单便捷。

4、在异步线程触发消息的情况下,能保证定时器回调的安全性(定时器宿主Obj和关联上下文数据的安全性)。

三、时间轮设计(间隔时间)

时间精度:accuracy = 50 (单位毫秒,自定义常量)

预期间隔时间:interval

实际间隔时间(accuracy倍数): interval = interval / accuracy + accuracy * int( interval % accuracy > 0)

四、业务obj对象设计

cpp 复制代码
class obj
{
    obj()
    {
        m_timer = new timer(mgr);
        // 成员方法指针方式触发定时器
        m_timer->open(start_time, interval, trigger_count, on_timer);  // 第①步
        // 匿名函数方式触发定时器
        m_timer->open(start_time, interval, trigger_count,    // 第①步
             []()
             {
              });
    };

    ~obj()
    {
        delete m_timer;
    };

    void on_timer()
    {
    };
};

五、定时器类设计

cpp 复制代码
class timer
{
    timer(mgr)
    {
        m_mgr = mgr;
    };

    ~timer()
    {
        clear();
    };

    uint64 open(start_time, interval, trigger_count, std:function<void(void)> callback)
    {
        auto id = m_mgr(this, start_time, interval, trigger_count, callback);  // 第②步
        m_timer_ids.add(id);
        return id;
    };

    void clear()
    {
        for (auto id : m_timer_ids)
        {
            m_mgr->close(id);
        }
        m_timer_ids.clear();
    };

    close(id)
    {
        m_timer_ids.del(id);
        m_mgr->close(id);
    };
};
复制代码

六、管理器类设计

cpp 复制代码
class timer_mgr
{
    uint64 open(timer, start_time, interval, trigger_count, callback)
    {
        auto id = ++id_count;
        interval = interval / accuracy + accuracy * int( interval % accuracy > 0)

        auto info = {id, timer, create_time, last_time, start_time, interval, trigger_count, callback};
        // 根据触发间隔时间来分类管理定时器(回调函数)
        auto infos = infos_by_interval.find(interval);
        infos.add(id, info);

        // 告诉定时器线程增加触发间隔时间
        timer_thread->add(interval); // 第③步

        return id;
    };

    close(id)
    {
        auto info = info_by_id.find(id);
        auto infos = infos_by_interval.find(info->interval);
        infos.del(id);
        info_by_id.del(id);
    };

    // 第⑤步
    trigger(interval)
    {
        auto infos = infos_by_interval.find(interval);
        for (auto info: infos)
        {
            // 检查是否有延时启动时间
            if (info->start_time)
            {
               if (get_tick_count()- info->create_time < info->create_time)
               {
                   continue;
                }
                // 下次不再进入本分支
                info->start_time = 0;
            }            

            // call定时器回调函数 第⑥步
            info->callback();
 
            // 检查定时器寿命
            info->trigger_count++;
            if (info->trigger_count == 0)
            {
               info->m_timer->m_timer_ids->del(id);
               infos .del(id);
            }
        }

        // 告诉定时器线程删除触发间隔时间
        if (infos->size() == 0)
        {
             timer_thread->del(interval);  // 第步
        }
    };
};
复制代码

七、定时器线程类设计

cpp 复制代码
class timer_thread
{
    void add(interval)
    {
        lock();
        if (!m_intervals.find(interval)) 
        {
            m_intervals.add(m_intervals, {interval, get_tick_count()});
        }
        unlock();
    }

    void del(interval)
    {
        lock();
        m_intervals.del(m_intervals);
        unlock();
    }

    void check()
    {
        auto now = get_tick_count();
        for (auto info: m_intervals)
        {
             if (now - info->last_time) >= info->interval)
             {
                  info->interval = now;
                  m_main_queue.push(info->interval);  // 第④步
             }
        }
    }

    // 线程启动省略
};
相关推荐
景天科技苑2 个月前
【Go】Go语言中延迟函数、函数数据的类型、匿名函数、闭包等高阶函数用法与应用实战
后端·golang·回调函数·defer·匿名函数·闭包·go函数数据类型
qq_172805592 个月前
GO 匿名函数
go·匿名函数
且听真言2 个月前
Flutter函数
函数的定义·匿名函数·可选参数·命名可选参数·位置可选参数·参数默认值·词法闭包
Trouvaille ~3 个月前
【Python篇】Python 函数综合指南——从基础到高阶
开发语言·python·生成器·异步函数·高阶函数·匿名函数·闭包
埜玊4 个月前
Python函数 之 匿名函数
python·匿名函数
zengk56210 个月前
四、Kotlin 表达式
匿名函数·kotlin 常量和变量·if-else 表达式·when 表达式·运算符重载函数·lambda 表达式·中缀表达式
微小冷1 年前
Julia函数进阶:匿名函数、函数复合、管道计算
julia·管道·函数式·匿名函数·函数复合·多参数
talk_81 年前
Jetpack:009-kotlin中的lambda、匿名函数和闭包
android·kotlin·lambda·匿名函数·闭包
闻缺陷则喜何志丹1 年前
C++前缀和算法应用:和至少为 K 的最短子数组的原理、源码及测试用例
c++·算法·前缀和·测试用例·二分·有序向量·匿名函数