【问题标题】:Javascript Typed array vs simple array: performanceJavascript 类型数组与简单数组:性能
【发布时间】:2017-10-27 22:38:23
【问题描述】:

我基本上想要做的是将一组数据点实时映射到 WebGL 顶点缓冲区 (Float32Array) 中(在动画参数表面上工作)。我假设用 Float32Arrays 表示数据点(每个组件一个 Float32Array:[xx...x,yy...y] 或交错它们:xyxy...xy)应该比将它们存储在数组中更快points: [[x, y], [x, y],.. [x, y]] 因为那实际上是一个嵌套的散列等等。然而,令我惊讶的是,这导致所有主要浏览器的速度降低了约 15%(不包括数组创建时间)。这是我设置的一个小测试:

var points = 250000, iters = 100;

function map_2a(x, y) {return Math.sin(x) + y;}
var output = new Float32Array(3 * points);

// generate data
var data = [];      
for (var i = 0; i < points; i++)
    data[i] = [Math.random(), Math.random()];
// run
console.time('native');
(function() {
    for (var iter = 0; iter < iters; iter++)
        for (var i = 0, to = 0; i < points; i++, to += 3) {
            output[to] = data[i][0];
            output[to + 1] = data[i][1];
            output[to + 2] = map_2a(data[i][0], data[i][1]);
        }
}());
console.timeEnd('native');

// generate data
var data = [new Float32Array(points), new Float32Array(points)];
for (var i = 0; i < points; i++) {
    data[0][i] = Math.random();
    data[1][i] = Math.random();
}
// run
console.time('typed');
(function() {
    for (var iter = 0; iter < iters; iter++)
        for (var i = 0, to = 0; i < points; i++, to += 3) {
            output[to] = data[0][i];
            output[to + 1] = data[1][i];
            output[to + 2] = map_2a(data[0][i], data[1][i]);
        }
}());
console.timeEnd('typed');

是不是我做错了什么?

【问题讨论】:

  • 这与您的问题无关,但您应该避免在主循环中进行乘法运算。而是在内部循环之前将一个额外的变量初始化为 0,并在每个内部循环块的末尾执行 += 3
  • 确保将每一个都放在它自己的上下文中,这样变量重新声明就不会引起问题。包装每个测试,将前 3 行排除在外,在 (function() { /* ... test ... */ })()
  • 你没有提到你用什么来对这些进行基准测试。请务必使用console.time,并确保仅包含// run 区域内的代码。没有理由假设 Math.random() 是常数时间。
  • @JosephLennox 是的,我曾经声明了一个特殊的测试函数,并且只将运行部分放入其中,但认为它不相关。感谢console.time,我发明了一辆小自行车来代替它。

标签: javascript arrays performance dynamic-arrays typed-arrays


【解决方案1】:

我认为您的问题是您没有比较相同的代码。在第一个示例中,您有一个用非常小的数组填充的大数组。在第二个示例中,您有两个非常大的数组,它们都需要被索引。个人资料不同。

如果我将第一个示例构造得更像第二个示例(两个大型泛型数组),那么Float32Array 实现的性能将远远优于泛型数组实现。

这里有一个jsPerf profile 来展示它。

【讨论】:

  • 虽然平心而论,但结果并不一致。对于无类型数组,我的速度要慢 6% 到 20%。
  • 并且,对于较小的数组,我发现通用数组在 Chrome 中的表现仍然略胜一筹。对于您提供的points,似乎是本地人更好。再上一个数量级,原生的就更好了。
  • 而当数组大小再高一个数量级(25000000)时,原生数组会破坏泛型数组。
  • 迭代次数似乎也很重要。一次通过,本机实现将其粉碎。通过 100 次,结果更接近一些。这会告诉我从两个数组读取性能更接近,但写入数组是实际节省的性能。
  • 嗯,是的,配置文件确实不同,但每个配置文件似乎都以一种自然的方式实现了相同的目标。无论如何,感谢您的深刻见解!
【解决方案2】:

在 V8 中,变量可以有 SMI (int31/int32)、双精度和指针类型。所以我想当你使用浮点数操作时,它应该被转换为双精度类型。如果您使用通常的数组,它已经转换为双精度数。

【讨论】:

    猜你喜欢
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 2016-04-22
    • 1970-01-01
    • 2019-10-30
    • 1970-01-01
    • 2020-01-28
    • 2011-09-21
    相关资源
    最近更新 更多