游戏服务器的帧率控制

news2024/12/23 7:24:18

固定Tick时间策略

在这里插入图片描述
固定Tick时间:顾名思义就是指程序每次心跳的时间都是等长的、固定的。如图中的“图A”,Tick1和Tick2的时间是相等的,如果实际执行的比上次执行时间长(Run2 > Run1),则Sleep2 < Sleep1,同时满足等式:Tick1 = Tick2 = Run1 + Sleep1 = Run2 + Sleep2

Mangos-Zero
mangos-zero项目中的逻辑服务进程mangosd的心跳函数采用的方法,当更新的处理时间Run1大于固定大小的tick时间时,下一个tick到来时不sleep直接执行Run2,实现代码如下:

   1: /// Heartbeat for the World
   2: void WorldRunnable::run()
   3: {
   4:     ///- Init new SQL thread for the world database
   5:     WorldDatabase.ThreadStart();     // let thread do safe mySQL requests (one connection call enough)
   6:     sWorld.InitResultQueue();
   7:  
   8:     uint32 realCurrTime = 0;
   9:     uint32 realPrevTime = WorldTimer::tick();
  10:  
  11:     uint32 prevSleepTime = 0;        // used for balanced full tick time length near WORLD_SLEEP_CONST
  12:  
  13:     ///- While we have not World::m_stopEvent, update the world
  14:     while (!World::IsStopped())
  15:     {
  16:         ++World::m_worldLoopCounter;
  17:         realCurrTime = WorldTimer::getMSTime();  //----------------(1)
  18:  
  19:         uint32 diff = WorldTimer::tick();        //--------------(2)
  20:  
  21:         sWorld.Update( diff );                   //--------------(3)
  22:         realPrevTime = realCurrTime;
  23:  
  24:         // diff (D0) include time of previous sleep (d0) + tick time (t0)
  25:         // we want that next d1 + t1 == WORLD_SLEEP_CONST
  26:         // we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement
  27:         // d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0
  28:         if (diff <= WORLD_SLEEP_CONST+prevSleepTime)    //----------------(4)
  29:         {
  30:             prevSleepTime = WORLD_SLEEP_CONST+prevSleepTime-diff;
  31:             ACE_Based::Thread::Sleep(prevSleepTime);
  32:         }
  33:         else
  34:             prevSleepTime = 0;
  35:  
  36:         #ifdef WIN32
  37:             if (m_ServiceStatus == 0) World::StopNow(SHUTDOWN_EXIT_CODE);
  38:             while (m_ServiceStatus == 2) Sleep(1000);
  39:         #endif
  40:     }
  41:  
  42:     sWorld.KickAll();                // save and kick all players
  43:     sWorld.UpdateSessions( 1 );      // real players unload required UpdateSessions call
  44:  
  45:     // unload battleground templates before different singletons destroyed
  46:     sBattleGroundMgr.DeleteAllBattleGrounds();
  47:  
  48:     sWorldSocketMgr->StopNetwork();
  49:  
  50:     sMapMgr.UnloadAll();             // unload all grids (including locked in memory)
  51:  
  52:     ///- End the database thread
  53:     WorldDatabase.ThreadEnd();       // free mySQL thread resources
  54: }

以上代码是游戏世界的主循环,看while循环里的代码,主要干下面几件事:

(1)从WorldTimer::getMSTime()得到一个uint32的值realCurrTime,realCurrTime是循环的(到增加到0xFFFFFFFF后,在增加就变成0),表示当前时间,单位是毫秒,是一个相对前一次tick的时间。

(2)使用WorldTimer::tick();计算上次tick到这次tick的时间差diff,该值理论上等于realCurrTime – realPrevTime

(3)sWorld.Update( diff );就是tick里的处理函数,游戏逻辑在这里得到更新处理。

(4)这里就是图所描述的,如果运行时间大于固定的tick时间,则不sleep继续占用CPU来处理更新,直到能在一个tick处理所有操作为止,这个时候才会sleep让出CPU时间片。

(5)WORLD_SLEEP_CONST就是固定的tick的时间长度,在这里是50ms

总结:现在可以回答本节前面的两个问题:在高负荷情况下mangos采用的方式提高服务器的响应速度,每个tick时间长度为50ms,也就是每秒钟更新20次,能满足更新的需求。

如果主逻辑循环是在调用epoll,那么可以利用epoll_wait的timeout参数进行代替sleep,实现如下:

        uint64_t prevSleepTime = 0;
        uint64_t curTime = 0;
        uint64_t prevTime = x_time::now_msec();
        while(!getTermnation())
        {
            curTime = x_time::now_msec();
            // t = tick , s = sleep 
            //diff = s0 + t0 , diff 是两次循环的间隔时间
            //希望一直保持 s1 + t1 = MAX_EPOLL_THREAD_TIMEOUT(100ms) , tick(t1)未知,但可以使用t0来作为参考值代替
            //s1 = MAX_EPOLL_THREAD_TIMEOUT - t1 = MAX_EPOLL_THREAD_TIMEOUT - t0 = MAX_EPOLL_THREAD_TIMEOUT - (diff - s0)
            uint64_t diff = 0;
            if(prevTime > curTime)
            {
                diff = 0xFFFFFFFFFFFFFFFF - (prevTime - curTime);
            }
            else
            {
                diff = curTime - prevTime;
            }
            //如果运行时间大于固定的tick时间,则不sleep继续占用CPU来处理更新,直到能在一个tick处理所有操作为止,这个时候才会sleep让出CPU时间片
            if(diff <= MAX_EPOLL_THREAD_TIMEOUT + prevSleepTime) // diff - s0 = t0 >= MAX_EPOLL_THREAD_TIMEOUT
            {
                prevSleepTime = MAX_EPOLL_THREAD_TIMEOUT - (diff - prevSleepTime);
            }
            else
            {
                prevSleepTime = 0;
            }
            prevTime = curTime;
            this->check_queue(epfd);
            int conns = epoll_wait(epfd,&events[0],MAX_EPOLL_EVENTS,prevSleepTime); //sleep
            if(getTermnation()) return true;
            for(int i=0;i<conns;i++) 
            {
                int fd = events[i].data.fd;
                x_tcp_task* task = (x_tcp_task*)events[i].data.ptr;
                if(events[i].events & EPOLLIN)
                {
                    task->ListenRecv();
                }
                else if(events[i].events & EPOLLOUT)
                {
                    task->ListenSend();
                }
            }
            this->update(diff);
        }
        return true;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/792661.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EventLog Analyzer:保障网络安全的强大日志审计利器

日志审计是现代网络安全中不可或缺的一环。随着信息技术的迅速发展&#xff0c;企业和组织面临着越来越多的网络安全威胁&#xff0c;如数据泄露、网络攻击和内部滥用等。而为了确保网络安全&#xff0c;日志审计成为了必要的措施。在众多日志审计工具中&#xff0c;EventLog A…

neo4j教程-安装部署

neo4j教程-安装部署 Neo4j的关键概念和特点 •Neo4j是一个开源的NoSQL图形存储数据库&#xff0c;可为应用程序提供支持ACID的后端。Neo4j的开发始于2003年&#xff0c;自2007年转变为开源图形数据库模型。程序员使用的是路由器和关系的灵活网络结构&#xff0c;而不是静态表…

个人博客系统[SpringBoot+SpringMVC+MyBais]

文章目录 &#x1f387; 前言1.项目目录介绍2.项目前准备2.1 使用到的第三方库2.1 配置文件&#xff08;application.properties&#xff09;2.2 数据库介绍 3.common目录工具类介绍3.1 AjaxResult类3.2 AppVariable类3.3 CaptchaUtils类3.4 PasswordUtils类3.5 UserSessionUti…

VSCode打开终端的方法

VScode打开终端的方法 第一种&#xff1a;快捷键 Ctrl ~ 第二种&#xff1a;选中某个文件&#xff0c;右键&#xff0c;点击“在集成终端中打开” 第三种&#xff1a;在VSCode的页面上方的选项&#xff0c;点击“终端”&#xff0c;再点击“新建终端” 打开后&#xff0c;…

事务,不只ACID

大家好&#xff0c;我是 方圆。一提到事务&#xff0c;最先让我想到的就是ACID和倒背如流的隔离级别。它确实和这些相关&#xff0c;但是在我读了《数据密集型应用系统设计》之后&#xff0c;我想把事务这个主题讲的不那么“传统”。本文的部分内容可能读起来会有些老生常谈的感…

【Vue】在el-table的el-table-column中,如何控制单行、单列、以及根据内容单独设置样式。例如:修改文字颜色、背景颜色

用cell-style表属性来实现。在官网中是这样表述这个属性的。 在el-table中用v-bind绑定此属性。&#xff08;v-bind的简写是&#xff1a;&#xff09; <el-table:data"options":cell-style"cell"><el-table-column prop"id" label"…

医疗小程序:提升服务质量与效率的智能平台

在医疗行业&#xff0c;公司小程序成为提高服务质量、优化管理流程的重要工具。通过医疗小程序&#xff0c;可以方便医疗机构进行信息传播、企业展示等作用&#xff0c;医疗机构也可以医疗小程序提供更便捷的预约服务&#xff0c;优化患者体验。 医疗小程序的好处 提升服务质量…

四章:Constrained-CNN losses for weakly supervised segmentation——弱监督分割的约束CNN损失函数

0.摘要 基于部分标记图像或图像标签的弱监督学习目前在CNN分割中引起了极大关注&#xff0c;因为它可以减轻对完整和繁琐的像素/体素注释的需求。通过对网络输出施加高阶&#xff08;全局&#xff09;不等式约束&#xff08;例如&#xff0c;约束目标区域的大小&#xff09;&am…

具身智能controller---RT-1(Robotics Transformer)(中---实验介绍)

6 实验 实验目的是验证以下几个问题: RT-1可以学习大规模指令数据&#xff0c;并且可以在新任务、对象和环境上实现zero-shot的泛化能力&#xff1f;训练好的模型可以进一步混合多种其他数据&#xff08;比如仿真数据和来自其他机器人的数据&#xff09;吗&#xff1f;多种方…

玄子Share - Redis 双系统安装教程 Linux Windows(附安装包)

玄子Share - Redis 双系统安装教程 Linux Windows&#xff08;附安装包&#xff09; Linux 安装 Redis 前置条件 Linux 本地体验需安装 Linux 虚拟机 Linux 安装 Redis 需学到第 15 节 【小白入门 通俗易懂】2021韩顺平 一周学会Linux https://www.bilibili.com/video/BV1Sv…

基于POX交叉的遗传算法求解车间调度

对于流水车间调度问题&#xff0c;n个工件在m台设备上加工&#xff0c;已知每个工件每个工序使用的机器和每个工件每个工序所用时间&#xff0c;通过决策每个机器上工件的加工顺序和每个工序的开始时间&#xff0c;使完成所有工序所用时间(makespan)最小。具有下列约束&#xf…

【计算机网络】应用层协议 -- HTTP协议

文章目录 1. 认识HTTP协议2. 认识URL3. HTTP协议格式3.1 HTTP请求协议格式3.2 HTTP响应协议格式 4. HTTP的方法5. HTTP的状态码6. HTTP的Header7. Cookie和Session 1. 认识HTTP协议 协议。网络协议的简称&#xff0c;网络协议是通信计算机双方必须共同遵守的一组约定&#xff0…

直线导轨的主要功能

直线导轨是一种常见的机械结构&#xff0c;用于工业机器人、数控机床和其他自动化装置中。它的作用是提供一个准确的直线运动轨道&#xff0c;使得设备能够在预定的路径上进行精确的移动。 直线导轨作为一种重要的机械基础件&#xff0c;在现代工业中得到了广泛的应用。它主要的…

双非二本想进嵌入式行业?

二本的话学历上会吃点亏&#xff0c;但也没有特别夸张。嵌入式毕竟是技术岗&#xff0c;主要还是看自己的技术能力。嵌入式的话&#xff0c;在北上广深&#xff0c;稍微好点的企业研究生学历都能开到20K以上&#xff0c;本科生会低个2K左右&#xff0c;像大疆、华为更高&#x…

Too many files with unapproved license: 2 See RAT report

解决方案 mvn -Prelease-nacos -Dmaven.test.skiptrue -Dpmd.skiptrue -Dcheckstyle.skiptrue -Drat.numUnapprovedLicenses100 clean install 或者 mvn -Prelease-nacos -Dmaven.test.skiptrue -Drat.numUnapprovedLicenses100 clean install

CPLD在线升级

文章目录 前言一、JTAG芯片介绍二、JTAG协议分析1.TAP状态机 前言 CPLD&#xff08;Complex Programmable Logic Device&#xff09;是一种可编程逻辑器件&#xff0c;可以用于实现数字逻辑电路的功能。CPLD通常包含可编程逻辑单元&#xff08;如逻辑门阵列&#xff09;和可编…

单向链表SingleLink

1.实现单向链表 public class SingleLink {private Node head;private int size;private class Node{private Object data;private Node next;public Node(Object data) {this.data data;}}public SingleLink() {// TODO Auto-generated constructor stubhead null;size 0;}…

Android 通用带箭头提示窗

简介 自定义PopupWindow, 适用于提示类弹窗。 使用自定义Drawable设置带箭头的背景&#xff0c;测试控件和弹窗的尺寸&#xff0c;自动设置弹窗的显示位置&#xff0c;让箭头指向锚点控件的中间位置&#xff0c;且根据锚点控件在屏幕的位置&#xff0c;自动适配弹窗显示位置。…

作为前端应该了解的后端常识

1、前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 什么是服务端 服务端&#xff0c;又称后端、server 端前端是用户可见、可操作的部分&#xff0c;如树枝树叶服务端为前端提供 “支撑”和 “营养”&…

Ubuntu22.04 locale出错

问题&#xff1a; locale: Cannot set LC_CTYPE to default locale: No such file or directory locale: Cannot set LC_MESSAGES to default locale: No such file or directory locale: Cannot set LC_ALL to default locale: No such file or directory 解决参考&#xff…