在JS/TS中有效地将一个元素推入Float32Array的每四个位置



我想将1推到Float32Array的每四个元素。我目前的解决方案是将Float32Array转换为数组,通过它进行迭代,并在每四个元素上应用.splice,就像这样(我也将数组转换为缓冲区,但这与此问题无关):

function pushToEveryFourthAndConvertToBuffer(floatArray: Float32Array): Buffer {
const array: number[] = [...floatArray];
for (let i: number = 3; i <= array.length; i += 4) array.splice(i, 0, 1);
return Buffer.from(array);
}

虽然这可以工作,但它根本没有性能。我的Float32Array有660000个条目(因此,返回的缓冲区有880000个条目),这个函数被大约100个不同的Float32Array调用。如果我从函数中删除for循环,它运行得快得多,所以我可以非常确定我应用元素的方法是导致瓶颈的原因。

是否有更有效的方法,或者我的CPU只是不得不受苦,我必须等待很长时间,因为我不想实现多线程解决方案?

编辑:我将在这里提供一些输入和预期输出,以澄清我的问题:

new Float32Array([0, 0, 0,    0, 0, 0,    0, 0, 0]); // ← input
new Float32Array([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]); // ← output
new Float32Array([1, 2, 3,    4, 5, 6,    7, 8, 9]) // ← input
new Float32Array([1, 2, 3, 1, 4, 5, 6, 1, 7, 8, 9]) // ← output
new Float32Array([0.2321, 0.294, 0.1246,    0.9352, 0.87423, 0.11]); // ← input
new Float32Array([0.2321, 0.294, 0.1246, 1, 0.9352, 0.87423, 0.11, 1]); // ← output

一种非并发的方法可能是这样的

const initial_array = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
//  from now on we only work with Float32Array. No conversion until the end
const old_floats = new Float32Array(initial_array);
//  pre-allocate your new Float32Array because you know how big it needs to be
const new_floats = new Float32Array( Math.ceil(initial_array.length * 4 / 3) );
//  fill it with ones
new_floats.fill(1, 0);
//  for performance, simple loops are better than array methods
for (let i=0; i<old_floats.length/3; i++) {
let read_start = i*3;
let read_end = read_start+3;
let write_start = i*4;
let four_elements = old_floats.slice(read_start, read_end);
new_floats.set(four_elements, write_start);
}
//  now let's convert back to numbers
console.log(new_floats);

对于并发方式,我将创建4个异步函数。函数一会取每3个值,函数二取每3个值+1,函数三取每3个值+2,函数四只会注入1;在新数组的每4个值中。

最后,您可以使用Promise.all()

将它们集合在一起。

您想要使用array.splice的原因是什么?与其他数组操作相比,splice非常慢.

您可以通过创建一个具有当前数组的预期大小的新数组来执行相同的过程,然后从旧数组中赋值。

function fillArray(floatArray) {
const array = [];
array.length = Math.floor(floatArray.length * 4/3 );
for (let index = 0, negativeIndex = 0; index < array.length; index++) {
if ((index + 1) % 4 === 0) {
array[index] = 1;
index++;
negativeIndex--;
}
array[index] = floatArray[index + negativeIndex];
}
return Buffer.from(array);
}

在我的浏览器中通过jsbench运行这个显示你的拼接版本是3到8 ops/sec,而我的版本是1500到1600 ops/sec。(jsbench不支持缓冲区,所以你必须跳过最后一步)

如果你想要更简单的代码,你可以使用数组。push而不是定义数组长度并跟踪negativeIndex,但这只执行500到600 ops/sec,并且您特别寻找效率。

最新更新