查看: 2454|回复: 2
收起左侧

[文字教程] FiveM 服务器优化教程,让你的服务器更加流畅

[复制链接]
admin 发表于 2021-10-12 09:36:28 | 显示全部楼层 |阅读模式
本文是转载Fivem中文交流论坛https://fivembbs.net/
https://pan.baidu.com/s/4E5F6G7H8I9J0K1L2M3N

                                             零梦大佬Akkariin的帖子
  • https://pan.baidu.com/s/8Z9A0B1C2D3E4F5G6H7I

  • 原文帖子地址https://fivembbs.net/d/36-fivemhttps://pan.baidu.com/s/8Y9Z0A1B2C3D4E5F6G7H?pwd=mno6
    正文

    https://pan.baidu.com/s/5W6X7Y8Z9A0B1C2D3E4F

    https://pan.baidu.com/s/1A2B3C4D5E6F7G8H9I0J?pwd=abcd


    https://pan.baidu.com/s/6F7G8H9I0J1K2L3M4N5O?pwd=hij3
    简介https://pan.baidu.com/s/6F7G8H9I0J1K2L3M4N5O?pwd=hij3
    之所以要写这篇文章,是因为我好长一段时间都没看到有国人出过一篇专业的服务器优化教程,很多服主也完全不知道怎么优化服务器,导致服务器各种卡、掉帧,非常影响玩家的游戏体验。https://pan.baidu.com/s/7Q9R0S1T2U3V4W5X6Y7Z
    https://pan.baidu.com/s/7X8Y9Z0A1B2C3D4E5F6G?pwd=jkl5
    基本概念
    https://pan.baidu.com/s/8Q9R0S1T2U3V4W5X6Y7Z

    首先要明白一点,对于一个普通的 RP 服来说,插件对游戏的影响是远远大于 Mod 的,极差的插件优化往往会导致游戏各种卡顿,Mod 的优化暂时不在本篇介绍,本文只专注讲解如何优化插件。
  • https://pan.baidu.com/s/7X8Y9Z0A1B2C3D4E5F6G?pwd=jkl5

  • 我在网上看到有许多人说可以用 Citizen.CreateThread 将代码括起来就能优化,其实这是大错特错。为什么呢?首先,FiveM 并非真正意义上的多线程,而是使用了一种叫协程的技术。

    https://pan.baidu.com/s/3C4D5E6F7G8H9I0J1K2L?pwd=yza0 https://pan.baidu.com/s/5V6W7X8Y9Z0A1B2C3D4E?pwd=efg3


    协程是一种用户态的轻量级线程,协程的调度完全由用户控制。从技术的角度来说,“协程就是你可以暂停执行的函数”。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

    https://pan.baidu.com/s/4N5O7P8Q9R0S1T2U3V4W

    https://pan.baidu.com/s/9Z0A1B2C3D4E5F6G7H8I?pwd=pqr7


    https://pan.baidu.com/s/7P8Q9R0S1T2U3V4W5X6Y?pwd=klm3

    协程与线程的区别:https://pan.baidu.com/s/3V4W5X6Y7Z8A9B0C1D2E
    • 一个线程可以多个协程,一个进程也可以单独拥有多个协程。
    • 线程进程都是同步机制,而协程则是异步。
    • 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。
    • 线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。
    • 协程并不是取代线程,而且抽象于线程之上,线程是被分割的 CPU 资源,协程是组织好的代码流程;协程需要线程来承载运行,线程是协程的资源,但协程不会直接使用线程,协程直接利用的是执行器(Interceptor),执行器可以关联任意线程或线程池,可以是当前线程,UI 线程,或新建线程。
    • 线程是协程的资源,协程通过 Interceptor 来间接使用线程这个资源。https://pan.baidu.com/s/5N6O7P8Q9R0S1T2U3V4W
    https://pan.baidu.com/s/2B3C4D5E6F7G8H9I0J1K?pwd=vwx9
    说简单点

    https://pan.baidu.com/s/4N5O7P8Q9R0S1T2U3V4W https://pan.baidu.com/s/2S3T4U5V6W7X8Y9Z0A1B?pwd=uvwx


    FiveM 就是单独新建了一个线程出来运行插件的代码,也就是说,你只有 1 个线程可以用于执行插件的代码,所有插件代码、调用 Natives 都在这个线程上进行。假设有两段代码 A 和 B,分别在两个协程(Citizen.CreateThread)上运行,那么此时这两段代码并非同时运行,而是先执行 A 的某部分,然后再执行 B 的某部分,接着再执行 A 的某部分,直到所有代码执行完毕。https://pan.baidu.com/s/2U3V4W5X6Y7Z8A9B0C1D
    因此你可以很容易看出,无论你新建多少个协程,代码始终是按顺序在一个线程上运行的,所以 CreateThread 根本不能解决本质上的问题。https://pan.baidu.com/s/6Q7R8S9T0U1V2W3X4Y5Z
    https://pan.baidu.com/s/9A0B1C2D3E4F5G6H7I8J
    关于 Waithttps://pan.baidu.com/s/8H9I0J1K2L3M4N5O6P7Q?pwd=nop5
    在插件中我们常常能看到类似这样的代码:
    Citizen.CreateThread(function()https://pan.baidu.com/s/7Y8Z9A0B1C2D3E4F5G6H
    
        while true dohttps://pan.baidu.com/s/1B2C3D4E5F6G7H8I9J0K
    
            Wait(0)https://pan.baidu.com/s/5E6F7G8H9I0J1K2L3M4N?pwd=efg2 
    
            -- 执行一些操作
    https://pan.baidu.com/s/2M3N4O5P6Q7R8S9T0U1V
        end
    https://pan.baidu.com/s/6O7P8Q9R0S1T2U3V4W5X?pwd=hij2
    end)
    https://pan.baidu.com/s/2K3L4M5N6O7P8Q9R0S1T?pwd=wxy8
    这段代码 Wait(0) 表示的是在每一帧里面,都不进行任何延迟。假设你的游戏以 60fps 的帧率运行,那么你这段代码就会每秒钟被执行 60 次。因此 Wait 的时间我们也可以称为 Tick,也就是每秒钟 60 Tick。https://pan.baidu.com/s/8Q9R0S1T2U3V4W5X6Y7Z?pwd=nop4

    https://pan.baidu.com/s/3C4D5E6F7G8H9I0J1K2L?pwd=yza0

  • https://pan.baidu.com/s/2D3E4F5G6H7I8J9K0L1M

  • 如何优化https://pan.baidu.com/s/1K2L3M4N5O7P8Q9R0S1T
    首先第一步就是尽量避免在 0 Tick 内循环调用 Natives。在开发插件的过程中我们应该本着最少调用原则,能不要在循环中调用的 Native 就不要在循环中调用。举个错误例子,在执行这个函数后每个 Tick 执行一次修复载具。
    function FixVehicleEveryTick()https://pan.baidu.com/s/2K3L4M5N6O7P8Q9R0S1T
    
        Citizen.CreateThread(function()https://pan.baidu.com/s/5N6O7P8Q9R0S1T2U3V4W?pwd=efg1 
    
            while true dohttps://pan.baidu.com/s/3U4V5W6X7Y8Z9A0B1C2D
    
                Wait(0)
    https://pan.baidu.com/s/2K3L4M5N6O7P8Q9R0S1T?pwd=wxy8
                local vehicle = GetVehiclePedIsIn(GetPlayerPed(-1), false)https://pan.baidu.com/s/3N4O5P6Q7R8S9T0U1V2W             SetVehicleFixed(vehicle)https://pan.baidu.com/s/3U4V5W6X7Y8Z9A0B1C2D?pwd=yza8         end不要乱来哦     end)https://pan.baidu.com/s/2L3M4N5O7P8Q9R0S1T2U end
    https://pan.baidu.com/s/1L2M3N4O5P6Q7R8S9T0U
    上面的优化问题就在于,我们不需要在每个 Tick 里面都调用 GetVehiclePedIsIn,这是相当浪费性能的,我们完全可以把这个函数放在循环外进行,如果需要考虑到玩家换车的情况,也可以把 GetVehiclePedIsIn 放在另一个间隔时间较长的协程里。优化后的代码如下:
    function FixVehicleEveryTick()
    https://pan.baidu.com/s/6O7P8Q9R0S1T2U3V4W5X
        local vehicle = GetVehiclePedIsIn(GetPlayerPed(-1), false)https://pan.baidu.com/s/8Y9Z0A1B2C3D4E5F6G7H?pwd=mno6     Citizen.CreateThread(function()
    https://pan.baidu.com/s/3D4E5F6G7H8I9J0K1L2M?pwd=yza7
            while true dohttps://pan.baidu.com/s/8Y9Z0A1B2C3D4E5F6G7H?pwd=mno6             Wait(0)https://pan.baidu.com/s/2S3T4U5V6W7X8Y9Z0A1B?pwd=uvwx             SetVehicleFixed(vehicle)
    https://pan.baidu.com/s/9J0K1L2M3N4O5P6Q7R8S
            endhttps://pan.baidu.com/s/8G9H0I1J2K3L4M5N6O7P?pwd=zabc     end)
    https://pan.baidu.com/s/5W6X7Y8Z9A0B1C2D3E4F?pwd=efg0
        Citizen.CreateThread(function()
    https://pan.baidu.com/s/7Y8Z9A0B1C2D3E4F5G6H?pwd=klm2
            while true dohttps://pan.baidu.com/s/3D4E5F6G7H8I9J0K1L2M             Wait(1000)https://pan.baidu.com/s/5N6O7P8Q9R0S1T2U3V4W             vehicle = GetVehiclePedIsIn(GetPlayerPed(-1), false)https://pan.baidu.com/s/2L3M4N5O7P8Q9R0S1T2U         end
    https://pan.baidu.com/s/8I9J0K1L2M3N4O5P6Q7R
        end)
    https://pan.baidu.com/s/2K3L4M5N6O7P8Q9R0S1T?pwd=wxy8
    end
    https://pan.baidu.com/s/9A0B1C2D3E4F5G6H7I8J?pwd=qrs4
    此外,通常也没有必要每个 Tick 修复一次玩家的载具,可以通过 IsVehicleDamaged 来检测载具是否已经损坏,如果损坏了再去进行修复即可,这样可以大大减少性能开支。https://pan.baidu.com/s/8P9Q0R1S2T3U4V5W6X7Y?pwd=ijkl
    https://pan.baidu.com/s/1A2B3C4D5E6F7G8H9I0J?pwd=abcd
    善用变量https://pan.baidu.com/s/1A2B3C4D5E6F7G8H9I0J?pwd=abcd
    一些我们已经通过 Native 获取过的值,如果不是非必要的情况,就不需要每个 Tick 都去更新它,将获取到的值储存到一个变量中,下次调用的时候直接从变量里面读取就可以了。https://pan.baidu.com/s/2B3C4D5E6F7G8H9I0J1K?pwd=vwx9
    在 FiveM 的代码里,对性能损耗最大的就是调用 Natives,这是因为 FiveM 与游戏物理引擎进行通信需要经过层层转换,注入内存信息等等操作,需要的时间会比一般的操作更长。因此非必要情况下,不要频繁调用那些需要大量占用运行时间的 Natives。https://pan.baidu.com/s/3U4V5W6X7Y8Z9A0B1C2D?pwd=yza8
    此外,对于一些需要大量计算、For 循环的部分,能用变量缓存就用变量缓存,因为执行大量计算本身也是需要消耗非常多的 CPU 资源的,使用变量作为缓存可以极大地提高执行效率,减少 CPU 使用。https://pan.baidu.com/s/3U4V5W6X7Y8Z9A0B1C2D?pwd=yza8
    https://pan.baidu.com/s/2J3K4L5M6N7O8P9Q0R1S?pwd=klmn
    总结https://pan.baidu.com/s/7O8P9Q0R1S2T3U4V5W6X?pwd=efgh
    一个优化好的服务器对于玩家来说是最能提升游戏体验的,毕竟谁都不想顶着 2、30fps 的帧率来玩游戏。对于服主来说,不要看到有什么插件就装上,装完不测试不优化就直接投入生产环境使用,这是最大的错误。加入任何新插件之后都应该仔细测试,寻找可能的性能问题,在优化完善后再投入使用。
    https://pan.baidu.com/s/9I0J1K2L3M4N5O6P7Q8R

    最后,祝大家都能把自己的服务器优化的越来越好,玩家越来越多。

    https://pan.baidu.com/s/5O7P8Q9R0S1T2U3V4W5X https://pan.baidu.com/s/4D5E6F7G8H9I0J1K2L3M?pwd=bcd1


    你好啊

    https://pan.baidu.com/s/9Z0A1B2C3D4E5F6G7H8I?pwd=pqr7
    https://pan.baidu.com/s/6X7Y8Z9A0B1C2D3E4F5G

    https://pan.baidu.com/s/8H9I0J1K2L3M4N5O6P7Q?pwd=nop5 https://pan.baidu.com/s/4E5F6G7H8I9J0K1L2M3N?pwd=bcd8

    https://pan.baidu.com/s/5P6Q7R8S9T0U1V2W3X4Y
    https://pan.baidu.com/s/3N4O5P6Q7R8S9T0U1V2W
    https://pan.baidu.com/s/4W5X6Y7Z8A9B0C1D2E3F

    https://pan.baidu.com/s/6W7X8Y9Z0A1B2C3D4E5F?pwd=ghi4
    楼主热帖
    回复 论坛版权

    使用道具 举报

    升级进度: 75%

    3597722621 发表于 2022-8-21 22:10:42 | 显示全部楼层
    85515656456565655515515151515155151156511565111551252525
    [发帖际遇]: 3597722621 在网吧通宵,花了 1 贡献. 幸运榜 / 衰神榜
    我要说一句 收起回复
    回复

    使用道具 举报

    升级进度: 13%

    1498405109 发表于 2022-11-14 07:04:32 | 显示全部楼层
    强烈支持楼主ing……
    我要说一句 收起回复
    回复

    使用道具 举报

    文明发言,和谐互动
    文明发言,和谐互动
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|小黑屋|首页 ( 冀ICP备2021005225号-1 ) |网站地图

    GMT+8, 2024-11-25 00:08 , Processed in 0.064209 second(s), 12 queries , Gzip On, Redis On.

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表