美文网首页程序员C#
C#实现一个帧调度器

C#实现一个帧调度器

作者: Aodota | 来源:发表于2023-02-18 11:41 被阅读0次

帧调度器

帧调度器 我们在写战斗,或者写房间类型的时候就需要一个按帧调度的调度器。

1. 抽象一个被调度器调度的单元

/// <summary>
/// 可更新对象
/// </summary>
public interface Updatable
{
    /// <summary>
    /// Id标识
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// 周期性update
    /// </summary>
    /// <param name="dt"></param>
    void Update(int dt);
}

2. 定义一个调度器

internal class UpdateExecutor
{
    /// <summary>
    /// 需要被调度的对象
    /// </summary>
    private List<Updatable>[] _updatables;

    /// <summary>
    /// 日志
    /// </summary>
    private Logger _log;

    /// <summary>
    /// 锁对象
    /// </summary>
    private object _lock;

    /// <summary>
    /// 当前游标
    /// </summary>
    private int _cursor;

    /// <summary>
    /// 运行的线程
    /// </summary>
    public System.Threading.Thread Thread { get; set; }

    /// <summary>
    /// 构造函数
    /// </summary>
    public UpdateExecutor(Logger log)
    {
        _updatables = new List<Updatable>[2];
        _updatables[0] = new List<Updatable>();
        _updatables[1] = new List<Updatable>();
        _log = log;
        _lock = new object();
        _cursor = 0;
    }

    public void Execute()
    {
        var start = TimeUtil.FastDateTimeNow; // 开始时间
        var interval = RoomScheduler.Interval;
        while (true)
        {
            var curr = TimeUtil.FastDateTimeNow; // 当前时间
            var frameDt = (int)(curr - start).TotalMilliseconds; // 帧间隔
            start = curr;

            RunFrame(frameDt);

            var execTime = (int)(TimeUtil.FastDateTimeNow - start).TotalMilliseconds;
            if (execTime < interval)
            {
                System.Threading.Thread.Sleep(interval - execTime);
            }
        }
    }

    private void RunFrame(int dt)
    {
        List<Updatable> updatables;
        lock(_lock)
        {
            updatables = _updatables[_cursor];
        }

        foreach(var updatable in updatables)
        {
            try
            {
                updatable.Update(dt);
            }
            catch (Exception e)
            {
                _log.Error(e, "run frame error, roomId:{0}", updatable.Id);
            }

        }
    }

    public void Schedule(Updatable updatable)
    {
        lock (_lock)
        {
            var newList = new List<Updatable>();
            newList.AddRange(_updatables[_cursor]);
            newList.Add(updatable);
            var cursor = 1 - _cursor;
            _updatables[cursor] = newList;
            _cursor = cursor;
        }
    }

    public void UnSchedule(Updatable updatable)
    {
        lock (_lock)
        {
            var newList = new List<Updatable>();
            newList.AddRange(_updatables[_cursor]);
            newList.Remove(updatable);
            var cursor = 1 - _cursor;
            _updatables[cursor] = newList;
            _cursor = cursor;
        }
    }
}

3. 定义调度器

/// <summary>
/// 调度器
/// </summary>
public class Scheduler
{
    /// <summary>
    /// Logger
    /// </summary>
    private static Logger Log = LogFactory.GetLog("com.will.gameroom");

    /// <summary>
    /// 帧间隔
    /// </summary>
    public static int Interval { get; set; } = 1000 / 1;

    /// <summary>
    /// 单例
    /// </summary>
    public static Scheduler Instance { get; } = new();

    private int _initFlag; // 初始化标志
    private UpdateExecutor[] _executors; // 执行器

    private Scheduler()
    {
    }

    /// <summary>
    /// 初始化
    /// </summary>
    /// <param name="threadNum"></param>
    public void Init(int threadNum = 2)
    {
        if (Interlocked.CompareExchange(ref _initFlag, 1, 0) == 0)
        {
            _executors = new UpdateExecutor[threadNum];
            for (var i = 0; i < threadNum; i++)
            {
                _executors[i] = new UpdateExecutor(Log);
                var currThread = new System.Threading.Thread(_executors[i].Execute);
                if (!currThread.IsAlive)
                {
                    currThread.Start();
                }

                _executors[i].Thread = currThread;
            }
        }
    }

    /// <summary>
    /// 加入调度
    /// </summary>
    /// <param name="updatable"></param>
    public void Schedule(Updatable updatable)
    {
        var mod = updatable.Id % _executors.Length;
        _executors[mod].Schedule(updatable);

        Log.Info("room#schedule#{0}", updatable.Id);
    }

    /// <summary>
    /// 移除调度
    /// </summary>
    /// <param name="updatable"></param>
    public void UnSchedule(Updatable updatable)
    {
        var mod = updatable.Id % _executors.Length;
        _executors[mod].UnSchedule(updatable);

        Log.Info("room#unschedule#{0}", updatable.Id);
    }
}

相关文章

  • C#实现一个帧调度器

    帧调度器 帧调度器 我们在写战斗,或者写房间类型的时候就需要一个按帧调度的调度器。 1. 抽象一个被调度器调度的单...

  • Kubernetes 调度器实现初探

    Kubernetes 调度器 Kubernetes 是一个基于容器的分布式调度器,实现了自己的调度模块。 在Kub...

  • Kubernetes 调度器实现初探

    Kubernetes 调度器 Kubernetes 是一个基于容器的分布式调度器,实现了自己的调度模块。 在Kub...

  • Python标准库sched模块介绍

    sched——通用时间调度器 sched模块实现了一个通用事件调度器,在调度器类使用一个延迟函数等待特定的时间,执...

  • Swift - RxSwift的使用详解20(调度器、subsc

    二十、调度器(Schedulers) 1,基本介绍 (1)调度器(Schedulers)是 RxSwift 实现多...

  • 调度器、subscribeOn、observeOn

    调度器(Schedulers) (1)调度器(Schedulers)是 RxSwift 实现多线程的核心模块,它主...

  • Quartz简单使用

    基础概念 Scheduler - 与调度器交互的主要API。 Job - 需要被调度器调度的任务必须实现的接口。 ...

  • Quartz初始化源码跟踪(3)

    正式初始化QuartzScheduler调度器接口及实现如下 StdScheduler 默认的调度器,其实就是Qu...

  • Keepalive之nginx调度架构

    单主模式Keepalive之Nginx 调度 实验目的: 实现Nginx调度的高可用,当一台Nginx调度器故障时...

  • go 调度器实现

    GO 语言的调度器 目录 GMP 模型简介 调度器实现机制 GMP 模型简介 先来一张经典的GMP 关系图 G 是...

网友评论

    本文标题:C#实现一个帧调度器

    本文链接:https://www.haomeiwen.com/subject/kyqbkdtx.html