Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/395.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
高性能javascript中的对象池?_Javascript_Performance - Fatal编程技术网

高性能javascript中的对象池?

高性能javascript中的对象池?,javascript,performance,Javascript,Performance,我正在编写一些javascript代码,这些代码需要快速运行,并且使用了大量短期对象。我最好使用对象池,还是根据需要创建对象 我写了一篇文章,指出使用对象池没有任何好处,但是我不确定jsperf基准测试是否运行足够长的时间,以便浏览器的垃圾收集器启动 代码是游戏的一部分,所以我不关心传统浏览器的支持。我的图形引擎无论如何都无法在旧浏览器上工作。对象池用于避免通过重新使用现有对象来创建新对象的实例化成本。只有当实例化对象的成本大于使用池所产生的开销时,这才有用 您已经证明,非常简单的对象不会从池中

我正在编写一些javascript代码,这些代码需要快速运行,并且使用了大量短期对象。我最好使用对象池,还是根据需要创建对象

我写了一篇文章,指出使用对象池没有任何好处,但是我不确定jsperf基准测试是否运行足够长的时间,以便浏览器的垃圾收集器启动


代码是游戏的一部分,所以我不关心传统浏览器的支持。我的图形引擎无论如何都无法在旧浏览器上工作。

对象池用于避免通过重新使用现有对象来创建新对象的实例化成本。只有当实例化对象的成本大于使用池所产生的开销时,这才有用


您已经证明,非常简单的对象不会从池中获益。随着对象变得更加复杂,这可能会发生变化。我的建议是遵循KISS原则,忽略对象池,直到对象创建速度被证明太慢。

对象池可能会有所帮助,特别是当您正在处理大量对象时。我最近就这个问题写了一篇文章,可能值得一读

一般来说(以我个人的经验),池对象不会提高速度。创建对象通常非常便宜。相反,对象池的目的是减少垃圾收集引起的周期性延迟

作为一个具体的例子(不一定是JavaScript,但作为一个通用的例子),请考虑使用高级3D图形的游戏。如果一个游戏的平均帧速率为60fps,那么这比另一个平均帧速率为40fps的游戏要快。但是,如果第二场比赛的fps始终为40,图形看起来很平滑,而如果第一场比赛的fps通常高于60 fps,但偶尔会下降到10 fps,图形看起来很起伏

如果您创建一个基准测试,运行两个游戏10分钟,并每隔一段时间采样一次帧速率,它将告诉您第一个游戏的性能更好。但它不会在波涛汹涌中恢复。这就是对象池要解决的问题

当然,这不是一个涵盖所有案例的笼统声明。当您经常分配大型阵列时,池不仅可以改善断断续续性,还可以改善原始性能:通过简单地设置
arr.length=0
并重用
arr
,您可以通过避免将来的重新调整大小来提高性能。类似地,如果您经常创建非常大的对象,这些对象都共享一个公共模式(即,它们有一组定义良好的属性,因此在将对象返回池时不必“清理”每个对象),那么在这种情况下,也可能会看到池的性能改进


正如我所说,一般来说,这不是对象池的主要目标。

我认为这取决于对象的复杂性。我最近优化了一个JavaScript字处理器,它为文档中的每个元素使用JS对象和DOM对象。在实现对象池之前,我的测试文档的加载时间约为480ms。池技术将其减少到220ms


这当然是个轶事,但在我的例子中,它大大增加了应用程序的快速性,我现在经常在对象周转率高的应用程序中使用池。

让我先说一句:我建议不要使用池,除非你正在开发可视化,游戏或其他计算昂贵的代码,实际上做了很多工作。你的web应用程序一般都是I/O绑定的,你的CPU和RAM大部分时间都是空闲的。在这种情况下,通过优化I/O而不是执行速度,您可以获得更多;i、 e.确保文件加载速度快,并且采用客户端而不是服务器端渲染+模板。然而,如果您正在玩弄游戏、科学计算或其他CPU绑定的Javascript代码,本文可能会让您感兴趣

短版

在性能关键代码中:

  • 从使用(以及更多)开始。不要马上跳进游泳池(你知道我的意思!)
  • 小心语法糖和外部库,因为即使是和许多内置(如等)也会在幕后做很多坏事,包括分配
  • 避免不可变(例如
    String
    ),因为在对其执行状态更改操作期间,这些将创建新对象
  • 了解你的分配。使用封装来创建对象,这样您就可以轻松地找到所有分配,并在分析期间快速更改分配策略
  • 如果您担心性能,请始终分析和比较不同的方法。理想情况下,你不应该随意相信intarwebz上的某个人(包括我)。请记住,我们对“快”、“长寿”等词的定义可能会有很大差异
  • 如果您决定使用池:
    • 对于长寿命对象和短命对象,可能必须使用不同的池,以避免短命池的碎片化
    • 您希望针对不同的场景比较不同的算法和不同的池粒度(池整个对象还是只池一些对象属性?)
    • 池增加了代码的复杂性,从而使优化器的工作更加困难,可能会降低性能
  • 长版本

    首先,考虑系统堆与大型对象池基本相同。这意味着,每当您创建一个新对象(使用

    new
    []
    {}
    ()
    、字符串串联等)时,系统都会使用一种(非常复杂、快速且低水平的性能调整)算法来为您提供一些未使用的空间(即对象),确保将其字节清零并返回它。这非常类似于一个物体
    var x = new X(...);
    
    var x = X.create(...);
    
    // this keeps all your allocation in the control of `Allocator`:
    var x = Allocator.createX(...);      // or:
    var y = Allocator.create('Y', ...);
    
    function add(a, b) { return new Vector(a.x + b.x, a.y + a.y); }
    // ...
    var z = add(x, y);
    
    function add(out, a, b) { out.set(a.x + b.x, a.y + a.y); return out; }
    // ...
    var z = add(x, x, y);   // you can do that here, if you don't need x anymore (Note: z = x)
    
    var tmp = new X(...);
    for (var x ...) {
        tmp.set(x);
        use(tmp);       // use() will modify tmp instead of x now, and x remains unchanged.
    }