tag tab page change javascript performance typed-arrays

tab - title of page javascript



Rendimiento de Javascript TypedArray (3)

En su caso, la razón del mal rendimiento es que intenta leer fuera de la matriz cuando utiliza Uint32Array debido a un error en la longitud de la matriz.

Pero si no fuera la verdadera razón entonces:

Intente usar Int32Array en lugar de Uint32Array. Creo que en V8 las variables no pueden tener el tipo uint32 pero pueden tener int32 / double / pointer. Por lo tanto, cuando asigne el tipo uint32 a la variable, se convertirá en un doble más lento.

Si utiliza la versión de V8 de 32 bits, las variables pueden tener el tipo int31 / double / pointer. Así que int32 se convertirá en doble también. Pero si utiliza la matriz habitual y todos los valores son int31, no es necesaria la conversión, por lo que la matriz habitual puede ser más rápida.

También el uso de int16 puede requerir algunas conversiones para obtener int32 (debido al signo y al complemento de unos). Uint16 no requerirá conversión porque V8 solo puede agregar ceros a la izquierda.

PD. Puede que te interesen los punteros y int31 (o int32 en x64) son las mismas cosas en V8. Esto también significa que int32 requerirá 8 bytes en x64. Además, esta es la razón por la que no hay un tipo int32 en x86: porque si usáramos los 32 bits para almacenar enteros, ya no tendríamos espacio para guardar los punteros.

¿Por qué los arreglos Typed no son más rápidos que los arreglos usuales? Quiero usar valores de precalc para CLZ (calcular la función de ceros a la izquierda). ¿Y no quiero que interpreten como objetos habituales?

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

Código de preparación:

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; };

Prueba 1:

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

Prueba 2:

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

PS Puede ser que mis exámenes de perf son inválidos, siéntase libre de corregirme.


Los motores modernos usarán matrices verdaderas detrás de las escenas, incluso si las usas si creen que pueden hacerlo, recurriendo a las "matrices" de mapas de propiedades si haces algo que les hace pensar que no pueden usar una verdadera matriz.

También tenga en cuenta que, como indica radsoc , var buffer = new ArrayBuffer(0x10000) luego var Uint32 = new Uint32Array(buffer) produce una matriz Uint32 cuyo tamaño es 0x4000 (0x10000 / 4), no 0x10000, porque el valor que le da a ArrayBuffer está en bytes, pero por supuesto hay cuatro bytes por entrada Uint32Array. Todo lo que sigue a continuación usa el new Uint32Array(0x10000) lugar (y siempre lo hizo, incluso antes de esta edición) para comparar manzanas con manzanas.

Así que empecemos por ahí, con el new Uint32Array(0x10000) : http://jsperf.com/array-access-speed-2/11 (lamentablemente, JSPerf ha perdido esta prueba y sus resultados, y ahora está completamente desconectado)

Eso sugiere que debido a que está llenando la matriz de una manera simple y predecible, un motor moderno continúa usando una verdadera matriz (con los beneficios de rendimiento de la misma) debajo de las cubiertas en lugar de cambiar. Vemos básicamente el mismo rendimiento para ambos. La diferencia en la velocidad podría estar relacionada con la conversión de tipo tomando el valor Uint32 y asignándolo como sum (aunque me sorprende que esa conversión de tipo no sea diferida ...).

Sin embargo, añade algo de caos:

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;

... de modo que el motor tenga que recurrir a los "arreglos" de mapas de propiedades pasados ​​de moda, y verá que los arreglos escritos superan notablemente al tipo anticuado: http://jsperf.com/array-access-speed-2/3 (lamentablemente, JSPerf ha perdido esta prueba y sus resultados)

Inteligentes, estos ingenieros de motores de JavaScript ...

Sin embargo, lo que hace específicamente con la naturaleza no matricial de la Array matrices es importante; considerar:

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;

Eso sigue llenando la matriz de manera predecible, pero le agregamos una propiedad que no es un elemento ( foo ). http://jsperf.com/array-access-speed-2/4 (lamentablemente, JSPerf ha perdido esta prueba y sus resultados) Al parecer, los motores son bastante inteligentes y mantienen esa propiedad sin elementos a un lado mientras continúan usa una verdadera matriz para las propiedades del elemento:

Estoy un poco perdido para explicar por qué las matrices estándar deberían ser más rápidas allí en comparación con nuestra primera prueba anterior. ¿Error de medición? Vagaries in Math.random ? Pero todavía estamos bastante seguros de que los datos específicos de la Array en la Array siguen siendo una verdadera matriz.

Mientras que si hacemos lo mismo pero completamos en orden inverso:

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;

... volvemos a las matrices mecanografiadas ganando, excepto en IE11: http://jsperf.com/array-access-speed-2/9 (lamentablemente, JSPerf ha perdido esta prueba y sus resultados)


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

no es lo mismo que

var Uint32 = new Uint32Array(0x10000);

no por el nuevo ArrayBuffer (siempre obtiene un búfer de matriz: vea Uint32.buffer en ambos casos) sino por el parámetro de longitud: con ArrayBuffer tiene 1 byte por elemento, con Uint32Array tiene 4 bytes por elemento.

Entonces, en el primer caso (y en su código), Uint32.length = 0x1000 / 4 y sus bucles están fuera de límites 3 de 4 veces. Pero lamentablemente nunca obtendrás errores, solo malas actuaciones.

Usando ''new ArrayBuffer'', tienes que declarar Uint32 así:

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

Consulte jsperf con (0x10000) y jsperf con (0x10000 * 4) .