Javascript TypedArray 性能

新手上路,请多包涵

为什么 TypedArrays 不比普通数组快?我想使用 CLZ 的预计算值(计算前导零函数)。而且我不希望他们解释为通常的对象?

http://jsperf.com/array-access-speed-22

准备代码:

  Benchmark.prototype.setup = function() {
   var buffer = new ArrayBuffer(0x10000);
   var Uint32 = new Uint32Array(buffer);
   var arr = [];
   for(var i = 0; i < 0x10000; ++i) {
     Uint32[i] = (Math.random() * 0x100000000) | 0;
     arr[i] = Uint32[i];
   }
   var sum = 0;
 };

测试 1:

 sum = arr[(Math.random() * 0x10000) | 0];

测试 2:

 sum = Uint32[(Math.random() * 0x10000) | 0];

在此处输入图像描述

PS:可能是我的性能测试无效,请随时纠正我。

原文由 Sukhanov Niсkolay 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 480
2 个回答
var buffer = new ArrayBuffer(0x10000);
var Uint32 = new Uint32Array(buffer);

与以下内容不同:

 var Uint32 = new Uint32Array(0x10000);

不是因为新的 ArrayBuffer (你总是得到一个数组缓冲区:见 Uint32.buffer 在这两种情况下)而是因为长度参数:与 ArrayBuffer -b-5553c每个元素一个字节,使用 Uint32Array 每个元素有 4 个字节。

因此,在第一种情况下(在您的代码中) Uint32.length = 0x1000/4 并且您的循环 4 次中有 3 次越界。但遗憾的是,您永远不会出错,只会出现糟糕的表现。

使用 new ArrayBuffer ,你必须像这样声明 Uint32 :

 var buffer = new ArrayBuffer(0x10000 * 4);
var Uint32 = new Uint32Array(buffer);

请参阅 带有 (0x10000) 的 jsperf带有 (0x10000 * 4) 的 jsperf

原文由 radsoc 发布,翻译遵循 CC BY-SA 4.0 许可协议

即使你使用 Array 现代引擎也会在幕后使用真正的数组,如果他们认为可以,如果你做了一些让他们认为他们不能使用真正数组的事情,就会回到属性映射“数组” .

Also note that as radsoc points out , var buffer = new ArrayBuffer(0x10000) then var Uint32 = new Uint32Array(buffer) produces a Uint32 array whose size is 0x4000 (0x10000 / 4), not 0x10000, because the value you give ArrayBuffer 以字节为单位,但当然每个 Uint32Array 条目有四个字节。以下所有内容都使用 new Uint32Array(0x10000) 来代替 (并且总是这样做,甚至在这次编辑之前) 来比较苹果与苹果。

因此,让我们从这里开始,使用 new Uint32Array(0x10000)http://jsperf.com/array-access-speed-211 (遗憾的是,JSPerf 丢失了这个测试及其结果,现在完全离线)

显示大致等效性能的图表

这表明,因为您以一种简单、可预测的方式填充数组,所以现代引擎继续在幕后使用真正的数组(具有其性能优势),而不是转移。我们看到两者的性能基本相同。速度上的差异可能与类型转换有关,采用 Uint32 值并将其分配给 sum 作为 number (尽管我对这种类型转换感到惊讶)不推迟…)。

不过,添加一些混乱:

 var Uint32 = new Uint32Array(0x10000);
var arr = [];
for (var i = 0x10000 - 1; i >= 0; --i) {
  Uint32[Math.random() * 0x10000 | 0] = (Math.random() * 0x100000000) | 0;
  arr[Math.random() * 0x10000 | 0] = (Math.random() * 0x100000000) | 0;
}
var sum = 0;

…因此引擎不得不退回到老式的属性映射“数组”,您会看到类型化数组明显优于老式数组: http://jsperf.com/array-access-speed-2 /3 (遗憾的是,JSPerf 丢失了这个测试及其结果)

条形图显示类型化数组的显着性能改进

聪明的是,这些 JavaScript 引擎工程师……

但是,您对 Array 数组的非数组性质所做的具体事情很重要;考虑:

 var Uint32 = new Uint32Array(0x10000);
var arr = [];
arr.foo = "bar";                            // <== Non-element property
for (var i = 0; i < 0x10000; ++i) {
  Uint32[i] = (Math.random() * 0x100000000) | 0;
  arr[i] = (Math.random() * 0x100000000) | 0;
}
var sum = 0;

这仍然可以预见地填充数组,但我们向其添加了一个非元素属性 ( foo )。 http://jsperf.com/array-access-speed-24 (遗憾的是,JSPerf 丢失了这个测试及其结果) 显然,引擎非常聪明,并且在继续的同时将非元素属性放在一边为元素属性使用真正的数组:

条形图显示当 <code>Array</code> 数组获得非元素属性时标准数组的性能改进

我有点不知所措,无法解释为什么与我们上面的第一个测试相比,标准阵列在那里应该变得 _更快_。测量误差? Math.random 变幻莫测?但我们仍然非常确定 Array 中的数组特定数据仍然是一个真正的数组。

而如果我们做同样的事情但填写相反的顺序:

 var Uint32 = new Uint32Array(0x10000);
var arr = [];
arr.foo = "bar";                            // <== Non-element property
for (var i = 0x10000 - 1; i >= 0; --i) {    // <== Reverse order
  Uint32[i] = (Math.random() * 0x100000000) | 0;
  arr[i] = (Math.random() * 0x100000000) | 0;
}
var sum = 0;

…我们回到类型化数组获胜的话题——IE11 除外:http: //jsperf.com/array-access-speed-29 (遗憾的是,JSPerf 丢失了这个测试及其结果)

显示除 IE11 之外的类型化数组获胜的图表

原文由 T.J. Crowder 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题