C#實(shí)現(xiàn)一個(gè)幀調(diào)度器

幀調(diào)度器

幀調(diào)度器 我們?cè)趯憫?zhàn)斗,或者寫房間類型的時(shí)候就需要一個(gè)按幀調(diào)度的調(diào)度器。

1. 抽象一個(gè)被調(diào)度器調(diào)度的單元

/// <summary>
/// 可更新對(duì)象
/// </summary>
public interface Updatable
{
    /// <summary>
    /// Id標(biāo)識(shí)
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// 周期性u(píng)pdate
    /// </summary>
    /// <param name="dt"></param>
    void Update(int dt);
}

2. 定義一個(gè)調(diào)度器

internal class UpdateExecutor
{
    /// <summary>
    /// 需要被調(diào)度的對(duì)象
    /// </summary>
    private List<Updatable>[] _updatables;

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

    /// <summary>
    /// 鎖對(duì)象
    /// </summary>
    private object _lock;

    /// <summary>
    /// 當(dāng)前游標(biāo)
    /// </summary>
    private int _cursor;

    /// <summary>
    /// 運(yùn)行的線程
    /// </summary>
    public System.Threading.Thread Thread { get; set; }

    /// <summary>
    /// 構(gòu)造函數(shù)
    /// </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; // 開始時(shí)間
        var interval = RoomScheduler.Interval;
        while (true)
        {
            var curr = TimeUtil.FastDateTimeNow; // 當(dāng)前時(shí)間
            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. 定義調(diào)度器

/// <summary>
/// 調(diào)度器
/// </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; // 初始化標(biāo)志
    private UpdateExecutor[] _executors; // 執(zhí)行器

    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>
    /// 加入調(diào)度
    /// </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>
    /// 移除調(diào)度
    /// </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);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容