【问题标题】:Javascript array unshift and pop operation for big dataset大数据集的 Javascript 数组 unshift 和 pop 操作
【发布时间】:2016-04-15 07:21:05
【问题描述】:

我有一个大数组用于存储数字(大小为 1000 或更多),这个数组值将用于实时渲染 y 轴线图。

我会不断地unshift 这个数组添加新数据,pop 删除数组中的最后一个数据。此操作允许我的图表从左向右移动。

但是,unshiftpop 的这种方法很简单,但是当我的数组大小增加并且我可能有超过 1 个图形时,它会导致内存碎片和时间性能,(第 n 个图形,每个包含一个的大阵列)。请问有没有更好的方法来做这个操作?

【问题讨论】:

  • 您对数组操作有任何性能问题,或者这只是理论上的问题?绘制图形比任何数组操作都更耗时。请注意,JavaScript 中的数组不一定是 JS 引擎中的标准数组——它们可以实现为列表或树,以执行 unshiftpop 操作。
  • 是一个理论问题,做这个操作让我很困扰,尤其是内存碎片问题......我想寻找其他更好的选择......
  • unshift 的性能远低于 push,因此您最好使用 pushshift 而不是 unshiftpop 并反向读取数组。我相信反向阅读也比直接阅读更快。还要检查一下.. code.stephenmorley.org/javascript/queues

标签: javascript arrays


【解决方案1】:

这个问题有两个方面:

有没有更好的方法来做这个操作?

这在很大程度上取决于您如何绘制图表。你为此使用某种图书馆吗?如果是这样,它可能需要一个特定的数据(例如数组),所以你无能为力。另一方面,如果你自己实现绘图部分,那么你可以使用任何你想要的数据结构(包括可能适合这里的列表)。

内存碎片和Array 性能

首先问自己一个问题:Array 操作是否真的存在任何性能问题,或者这只是理论上的问题?

绘制图形比任何数组操作都更耗时。我认为你不应该担心 Array 方法的性能,除非你真的对它们有任何问题。请注意在 JS 引擎中 Arrays 不一定实现为数组。它们可能是二叉搜索树,甚至是其他东西,具体取决于您如何使用它们,因此很难预测哪些优化对您的情况有效,哪些会使事情变得更糟。

有什么方法可以提高性能?

是的。但这取决于您实际使用数组的方式。我可以想象如果您绘制实时图表和unshift/pop 数据,例如。每隔 1 秒,您就知道数组的 length,对吗?它应该保持不变。因此,您可以做的一件事是,在开始时,为该长度的数组分配内存。如果您将来执行unshift + pop,您的内存不应该碎片化,因为这是引擎优化的简单案例。但话又说回来,这只是猜测,因为 JavaScript 引擎比我聪明。更多提示和技巧在文章Let’s get those Javascript Arrays to work fast中进行了描述。

不要试图修复没有损坏的东西。在开始重构之前进行测量,不要过度思考。这称为过早优化,我敢肯定,当您实际运行应用程序时,数组操作不会成为优化的优先级。

【讨论】:

  • 不错的答案!实际上是您分享的链接让我陷入了这种想法,您提到一旦分配数组unshiftpop 操作不会导致内存碎片,为什么?
  • 我说的是不应该,因为这很容易被引擎优化。但目前尚不清楚实际会发生什么,您必须在代码库中自行检查。
【解决方案2】:

我很好奇,可以针对传统的同内存复制测量移位/推送,结果很清楚,不需要优化。

var p = [], q = [];
for (var i = 0; i < 10000; i++) p[i] = i;
for (var i = 0; i < 10000; i++) q[i] = i;

function rotate_1(a, x) {
  var len = a.length;
  for (var i = 1; i < len; i++) 
    a[i - 1] = a[i]; 
  a[len - 1] = x;
}

function rotate_2(a, x) {
  a.shift();
  a.push(x);
}

t = new Date()
for (var i = 0; i < 100000; i++) rotate_1(p, i);
document.write("copy=");
document.write(new Date() - t);
document.write("<br>");

t = new Date()
for (var i = 0; i < 100000; i++) rotate_2(q, i);
document.write("shift/push=");
document.write(new Date() - t);
document.write("<br>");

【讨论】:

  • 其实挺有意思的。在对非常大的数组进行操作时,将push 加入数组并增加开始迭代的索引会更快,还是先删除一个元素再添加一个元素会更好?第二种方法不应该导致任何内存碎片,并且从常量索引(在本例中为 0)开始的循环更容易被 JS 引擎优化。
  • @MichałMiszczyszyn:哎呀,看来我误读了这个问题。他希望每次都添加新数据,而不是循环。
猜你喜欢
  • 1970-01-01
  • 2015-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多