Javascript TypedArray性能

Suk*_*lay 20 javascript performance typed-arrays

为什么TypedArrays不像通常的数组那么快?我想为CLZ使用precalc值(计算前导零函数).而且我不希望他们像往常一样解释对象?

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

准备代码:

 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;
 };
Run Code Online (Sandbox Code Playgroud)

测试1:

sum = arr[(Math.random() * 0x10000) | 0];
Run Code Online (Sandbox Code Playgroud)

测试2:

sum = Uint32[(Math.random() * 0x10000) | 0];
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

PS可能是我的性能测试无效随时纠正我.

T.J*_*der 35

现代引擎将在幕后使用真正的数组,即使你Array认为他们可以使用它们,如果你做了让他们认为不能使用真正数组的东西,那么就回到属性映射"数组".

还要注意,当radsoc指出时,var buffer = new ArrayBuffer(0x10000)然后var Uint32 = new Uint32Array(buffer)产生一个Uint32数组,其大小为0x4000(0x10000/4),而不是0x10000,因为你给出的值ArrayBuffer是以字节为单位,但当然每个Uint32Array条目有4个字节.所有的下方使用new Uint32Array(0x10000),而不是(和往常一样,即使此编辑之前)与苹果比较苹果.

所以让我们从那里开始new Uint32Array(0x10000):http ://jsperf.com/array-access-speed-2/11(遗憾的是,JSPerf已经失去了这个测试及其结果,现在完全脱机)

图表显示大致相同的性能

这表明,由于您以简单,可预测的方式填充阵列,现代引擎继续使用真正的阵列(具有其性能优势)而不是转移.我们看到两者的表现基本相同.速度的差异可能与获取Uint32值并将其分配sum为a的类型转换有关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;
Run Code Online (Sandbox Code Playgroud)

...所以引擎必须依赖于老式的属性映射"数组",你会发现类型化的数组明显优于传统类型: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;
Run Code Online (Sandbox Code Playgroud)

这仍然可以预测地填充数组,但是我们foo为它添加了一个非元素属性().http://jsperf.com/array-access-speed-2/4 (遗憾的是,JSPerf已经失去了这个测试及其结果)显然,引擎非常聪明,并且将这些非元素属性保留在一边,同时继续对元素属性使用true数组:

条形图显示<code>Math.random</code>?但我们仍然非常确定该数组中特定于阵列的数据<code>Array</code>仍然是一个真正的数组.</p>

<p>然而,如果我们做同样的事情,但填写相反的顺序:</p>

<pre><code>var Uint32 = new Uint32Array(0x10000);
var arr = [];
arr.foo = Run Code Online (Sandbox Code Playgroud)

...我们回到打出的类型阵列 - 除了IE11:http ://jsperf.com/array-access-speed-2/9(遗憾的是,JSPerf已经失去了这个测试及其结果)

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

  • 有意思,谢谢.在实际使用情况下,事情变得更加复杂,其中各种对象/阵列的连续分配/解除分配导致存储器碎片,并且如果未预先分配存储器,则处理时间爆炸.在现实生活中,Typed Array会因为预分配而花费更少(Rq:js Arrays也可能预先分配...) (3认同)

rad*_*soc 34

var buffer = new ArrayBuffer(0x10000);
var Uint32 = new Uint32Array(buffer);
Run Code Online (Sandbox Code Playgroud)

与以下内容不同:

var Uint32 = new Uint32Array(0x10000);
Run Code Online (Sandbox Code Playgroud)

不是因为新的ArrayBuffer(你总是得到一个数组缓冲区:在两种情况下都看到Uint32.buffer)但由于长度参数:对于ArrayBuffer,每个元素有1个字节,Uint32Array每个元素有4个字节.

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

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

var buffer = new ArrayBuffer(0x10000 * 4);
var Uint32 = new Uint32Array(buffer);
Run Code Online (Sandbox Code Playgroud)

请参阅jsperf(0x10000)jsperf(0x10000*4).

  • 令人遗憾的是,人们接受基于内容大小的答案,而不是正确性. (3认同)