草庐IT

javascript - 测量四个相似 Javascript 函数之间的 CPU 负载差异

coder 2024-07-20 原文

为什么这对我很重要

我有一个网站,我需要在其中运行倒数计时器,以向人们显示他们还剩多少时间来完成一项操作。

这个计时器将运行数天,可能只是使用 MomentJS 从 MomentJS 的 to() 中说“4 天后”之类的话。功能。

但是,当我们还剩一个小时时,我将切换到按分钟计时器倒计时,最终当分钟数足够低时,我将使用秒计时器。当我们进入最后几分钟时,我什至要显示毫秒。

问题

几乎有两种主要技术可以为倒数计时器设置动画。

  • setInterval()
  • requestAnimationFrame()

  • 好吧,我马上注意到 requestAnimationFrame()方法对眼睛来说更加流畅,效果很好 - 特别是当我显示毫秒时。然而没过多久,我注意到我那台糟糕的电脑开始变得有点热了。所有这些“动画”都给我的 CPU 造成了相当大的负载。我尝试使用 CPU 监视器,并环顾四周,看看这给我的 CPU 带来了多少负载,但总的来说,我真的找不到一个工具可以让我清楚地了解我的小倒数计时器的 CPU 负载类型使用。

    所以,我决定找到一种方法来限制 FPS,看看这是否会减少我的问题。是的,确实如此。如果您使用 setTimeout()requestAnimationFrame() 串联您可以在调用下一个函数之前设置等待时间。

    如果您使用的是 setTimeout(),这就提出了一个问题。 - 为什么不直接使用 setInterval()忘记 requestAnimationFrame() 的额外优化给你?

    我环顾四周,发现了另一种方法,它只是检查自上次 requestAnimationFrame() 以来是否已经过去了合适的间隔时间。调用你的函数。我对这段代码的工作方式做了一些优化,最终得到了我在下面尝试测量的两个函数之一。

    最后,我真的很想有一个更清晰的方法来衡量这个 - 因为我的 Mac 上的事件监视器几乎不是提供准确读数的可靠工具 - 而且我找不到一种方法来衡量我的代码正在运行。

    Chrome 有一些更多的工具、分析器和时间线——它们都非常有用,但它们没有给我我正在寻找的指标——CPU 负载。

    编码:

    这里有四个代码片段,它们做的完全一样——它们都使用:
  • MomentJS
  • CountdownJS
  • jQuery

  • 代码 100% 相同,唯一的区别是我如何限制动画的 FPS。

    我想找到一种方法来(尽可能精确地)测量四个函数之间在它们所占用的 CPU 负载方面的差异。然后我想更改 FPS 以查看我是否可以为我的应用程序找到可接受的负载,然后我可以找到最佳点 - 在不同的计时器阶段期间正确的 FPS 数量。

    技术 1 - setTimeout()

    var now = moment(); // new Date().getTime();
    var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
    
    $(".now").text(moment(now).format('h:mm:ss a'));
    $(".then").text(moment(then).format('h:mm:ss a'));
    $(".duration").text(moment(now).to(then));
    
    (function timerLoop() {
      setTimeout(function(){
        $(".difference").text(moment().to(then));
        $(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
        requestAnimationFrame(timerLoop);
      }, 1000/30);
    })();
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
    <script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
    <script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
    <div>
      The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
    </div>
    <div>The timer is set to go off <span class="difference"></span></div>
    <div class="countdown"></div>


    技术 2 - 间隔之间的增量

    var now = moment(); // new Date().getTime();
    var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
    
    $(".now").text(moment(now).format('h:mm:ss a'));
    $(".then").text(moment(then).format('h:mm:ss a'));
    $(".duration").text(moment(now).to(then));
    
    var fps = 30;
    var interval = 1000/fps;
    var performanceTime = performance.now();
    var performanceDelta;
    
    (function updateCountdown(time) {
      performanceDelta = time - performanceTime;
      if (performanceDelta > interval) {
        performanceTime = time - (performanceDelta % interval);
        $(".difference").text(moment().to(then));
        $(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
      }
      requestAnimationFrame(updateCountdown);
    })();
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
    <script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
    <script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
    <div>
      The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
    </div>
    <div>The timer is set to go off <span class="difference"></span></div>
    <div class="countdown"></div>


    技术 3 - setInterval()

    var now = moment(); // new Date().getTime();
    var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
    
    $(".now").text(moment(now).format('h:mm:ss a'));
    $(".then").text(moment(then).format('h:mm:ss a'));
    $(".duration").text(moment(now).to(then));
    
    var fps = 30;
    var interval = 1000/fps;
    
    setInterval(function updateCountdown() {
        $(".difference").text(moment().to(then));
        $(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
    }, interval);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
    <script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
    <script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
    <div>
      The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
    </div>
    <div>The timer is set to go off <span class="difference"></span></div>
    <div class="countdown"></div>


    看到这样一个完全不受限制的版本也会很有趣:

    技巧 4 - 无 throttle

    var now = moment(); // new Date().getTime();
    var then = moment().add(60, 'seconds'); // new Date(now + 60 * 1000);
    
    $(".now").text(moment(now).format('h:mm:ss a'));
    $(".then").text(moment(then).format('h:mm:ss a'));
    $(".duration").text(moment(now).to(then));
    (function timerLoop() {
      $(".difference").text(moment().to(then));
      $(".countdown").text(countdown(then, null, countdown.YEARS | countdown.MONTHS | countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS | countdown.MILLISECONDS).toString());
      requestAnimationFrame(timerLoop);
    })();
    
    // CountdownJS: http://countdownjs.org/
    // MomentJS: http://momentjs.com/
    // jQuery: https://jquery.com/
    // Rawgit: http://rawgit.com/
    // Light reading about the requestAnimationFrame pattern:
    // http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
    // https://css-tricks.com/using-requestanimationframe/
    <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js" type="text/javascript"></script>
    <script src="https://cdn.rawgit.com/mckamey/countdownjs/master/countdown.min.js" type="text/javascript"></script>
    <script src="https://code.jquery.com/jquery-3.0.0.min.js" type="text/javascript"></script>
    <div>
      The time is now: <span class="now"></span>, a timer will go off <span class="duration"></span> at <span class="then"></span>
    </div>
    <div>The timer is set to go off <span class="difference"></span></div>
    <div class="countdown"></div>



    简单地说:如何测量四个类似的 javascript 函数之间的 CPU 负载差异?

    有没有人已经知道其中哪一个会更高效? (我知道这不是一个词)

    最佳答案

    回答我自己的问题:

    简短的回答:

  • 最差性能

    Clearly setInterval() is the worst solution. Because setInterval() still runs while you are not on the tab, wasting CPU and therefor battery life.

  • 最佳动画(微秒)

    Clearly the Delta Interval Math calculation method is the most smooth and most accurate way to calculate interval time. When you combined this algorithm with the accuracy of calculating frames times using performance.now() you can achieve results accurate to the microsecond with your animation frames.

    (and yes, even requestAnimationFrame() uses performance.now() time as the first argument it passes to the callback function).

    And yes folks, I really mean microseconds. That's 1s/1000ms/1000µs.

    Go ahead, test it now. Open up your console and type: performance.now() And you'll get a number that looks like 2132438.165 - those are milliseconds since the browser rendered the first frame.

    (Which is extra cool because µ is a greek character +10 nerd points)

  • 最佳 CPU 性能(毫秒)

    Combine requestAnimationFrame() (which allows your animation to sleep when you switch tabs) with setTimeout() which can throttle the FPS of your animation to any desired millisecond interval.

    Keep in mind however, that the difference between this method and the Delta Interval Math method is very VERY slightly different. I don't even have a way to quantify how small of a difference it is. From what I can tell it might be one fourth to one eighth more efficient. But you lose a lot of smoothness for it. your choice.



  • 长答案:

    我仍然期待有更好的方法来做到这一点,也许是一种允许我比较不同功能之间数据的方式。

    在那之前,我能够使用 Google's Javascript CPU Profiler 生成这些图像

    按照我认为它们具有性能的顺序列出,但标题与原始问题相匹配:

    技术 3 - setInterval()


    技术 1 - setTimeout()


    技术 2 - 间隔之间的增量


    技术 4 - 无 throttle


    视觉分析

    好吧,从它的外观来看,我会按照以下性能顺序对不同的功能进行排名:
  • setInterval() 函数。
  • setTimeout() wrapping the requestAnimationFrame()` 调用。
  • requestAnimationFrame()
  • 调用的递归函数内的Delta Interval Math
  • 没有 FPS Throttle 简单地循环使用 requestAnimationFrame()

  • 结论:[编辑:06/25/2016]
    setInterval() 函数比我发现的任何 requestAnimationFrame() 模式都要好,至少由于 CPU 使用原因 只有当你在选项卡上时

    因此,如果 CPU 成本为 或更长 电池生命周期 是您的应用程序的更大问题,而不是使用 requestAnimationFrame() 并使用以下任一方法限制 FPS:
  • setTimeout() 方法对 CPU 的工作量似乎要少一些(两全其美) - 但诚然不如下面的方法流畅。
  • Delta Interval Math 看起来更平滑一点动画(并使用此问题/答案中的技术概述,时间从 performance.now() 和从 requestAnimationFrame() 报告的时间(这只是当前 0679104 中提供的第一个参数到回调函数。因为我们使用了我见过的最准确的算法来计算动画帧(您实际上计算的是百万分之一秒,或微秒 1s/1000ms/1000µs)。有这种技术和 performance.now() 在 CPU 负载方面没有巨大差异 - 但有区别(引用附图)

  • 为什么 setTimeout() 是炸弹数字?” - 因为: 当您不在该选项卡上时,它会被浏览器关闭,因此您的动画正在“等待”您回来。并使用 performance.now () 你的动画精度达到了微秒 (µs)。

    It is said requestAnimationFrame() 是一种“优化”方式,可确保您的动画与其他浏览器重绘一起工作,以便您的动画“适合”浏览器正在执行的操作,它还需要 60FPS 的回调成本。

    我用来生成这些照片的步骤:
  • 创建了单独的空白 HTML 文件,只包含我测试所需的内容。
  • 重新启动我的电脑,只打开我的 chrome 浏览器到 requestAnimationFrame() 选项卡。
  • 打开我之前单独创建的每个“测试基准”HTML 文件,一次一个。
  • 在倒数计时器刚好 50 秒时,我在 Google's Javascript CPU Profiler 上单击了 about:blank,10 秒后我单击了 start(我使用了一个内置于我的 gamer-mouse's5 的特殊单击宏,我的 driver software5 单击它非常好用 -x101616104010401040107915几秒钟后,再次点击 stop - 对于这些照片来说已经足够了)
  • 将配置文件保存到我的电脑
  • 将每个配置文件加载到 start 选项卡上的分析器工具中。
  • 调整窗口大小以将数据框起来
  • 屏幕截图 stop 然后你在键盘上按 about:blank 将屏幕截图精确地框在窗口周围。


  • Unresolved 问题:

    我仍然没有办法查看 CPU 使用率是多少。这张图让我想要更详细的东西。其他 Google Javascript CPU Profiler 屏幕在这个意义上也有点模糊。也许我只是不知道如何使用该工具。

    如果有人知道更好的测试基准,请发送答案,我会审查它。我希望它比这个烂摊子好。并提前致谢。

    这里的主要问题是有一种方法可以量化从一个 CPU 配置文件到另一个 CPU 配置文件的硬数据并进行比较。这是我最缺的。

    关于javascript - 测量四个相似 Javascript 函数之间的 CPU 负载差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38024288/

    有关javascript - 测量四个相似 Javascript 函数之间的 CPU 负载差异的更多相关文章

    1. ruby - 将差异补丁应用于字符串/文件 - 2

      对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

    2. ruby-on-rails - Rails 应用程序之间的通信 - 2

      我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

    3. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

      我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

    4. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

      我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

    5. ruby - 在 Ruby 中有条件地定义函数 - 2

      我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

    6. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

      在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

    7. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

      我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

    8. ruby - 在 Ruby 中按名称传递函数 - 2

      如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

    9. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

      说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

    10. [工业相机] 分辨率、精度和公差之间的关系 - 2

      📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

    随机推荐