简体   繁体   中英

Fastest way to copy typedarray to array in javascript?

The straightforward way to do it is with a for-loop:

function copy(a, t, start, end) {
    for (var j = start; j < end; j++) {
        a[j] = t[j];
    }
}

I thought a better implementation would be to use spreads + splice:

function copy_splice(a, t, start, end) {
    a.splice(start, end - start, ...t.slice(start, end));
}

However, when I test this with the following code, I get significantly worse performance:

function randArray(length) {
    var result = [];
    for (var j = 0; j < length; j++) {
        result.push(Math.floor(60000 * Math.random()));
    }
    return result;
}

function test_func(copy_func) {
    [10, 100, 1000, 100000].forEach(function (length) {
        var a = randArray(length);
        const t = new Int32Array(randArray(length));
        const start = length / 10;
        const end = length / 2;

        const time_start = performance.now();
        for (var repeats = 0; repeats < 500; repeats++) {
            copy_func(a, t, start, end);
        }
        const time_end = performance.now();
        console.log(copy_func.name + ' timing: ' + (time_end - time_start));
    });
}

// Test first
var a1 = randArray(100);
var a2 = a1.slice();
var t = new Int32Array(randArray(100));
copy(a1, t, 10, 50);
copy_splice(a2, t, 10, 50);
console.assert(a1.reduce((a, b) => a + b, 0) == a2.reduce((a, b) => a + b, 0));


test_func(copy);
test_func(copy_splice);

Results in Firefox:

copy timing: 1
copy timing: 0
copy timing: 37
copy_splice timing: 4
copy_splice timing: 20
copy_splice timing: 1140

Results in Nodejs:

copy timing: 0.08499000035226345
copy timing: 1.3703359998762608
copy timing: 0.8646280001848936
copy timing: 24.584946000017226
copy_splice timing: 0.8248800002038479
copy_splice timing: 2.532259000465274
copy_splice timing: 5.594846999272704
copy_splice timing: 529.5111650004983

So:

  1. Is there any better implementation than these mentioned above?
  2. (optional) Why are array spreads + .splice performing worse here?

Often a plain, old-style for loop will outperform alternatives. The reason why the spread syntax performs worse is that there is a lot of overhead:

  1. t.slice() creates a new array
  2. ... calls the array iterator in order to retrieve values from that array
  3. All these arguments are placed on the stack in the context of the splice function call
  4. splice replaces the elements one by one, much like the for loop solution
  5. splice also collects the replaced elements in a new array, and returns that array.

As you can see, the for loop solution only needs to deal with point 4, but not with anything that relates to the other points.

Possibly a smart JavaScript engine can optimise away some of the redundant work described above, but the evidence you see, proves that (currently) such optimisation does not bring the efficiency of the plain for loop.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM