简体   繁体   English

将重复序列复制到TypedArray的更有效方法?

[英]More efficient way to copy repeating sequence into TypedArray?

I have a source Float32Array that I create a secondary Float32Array from. 我有一个源Float32Array ,可Float32Array创建辅助Float32Array I have a sequence of values model that I want to copy as a repeating sequence into the secondary Float32Array . 我有一个值序列model ,我想将其作为重复序列复制到辅助Float32Array I am currently doing this operation using a reverse while loop. 我目前正在使用反向while循环进行此操作。

sequence = [1, 0, 0, 0, 0, 1, 0, 0, 2, 0, 1, 0];
n = 3179520; //divisible by sequence length
modelBuffs = new Float32Array(n);

var v = modelBuffs.length;

while(v-=12){
  modelBuffs[v-12] = sequence[0];
  modelBuffs[v-11] = sequence[1];
  modelBuffs[v-10] = sequence[2];
  modelBuffs[v-9] = sequence[3];

  // YTransform
  modelBuffs[v-8] = sequence[4];
  modelBuffs[v-7] = sequence[5];
  modelBuffs[v-6] = sequence[6];
  modelBuffs[v-5] = sequence[7];

  // ZTransform
  modelBuffs[v-4] = sequence[8];
  modelBuffs[v-3] = sequence[9];
  modelBuffs[v-2] = sequence[10];
  modelBuffs[v-1] = sequence[11];
}

Unfortunately, n can be unknown. 不幸的是, n可能是未知的。 I may have to do a significant refactor if there is no alternative solution. 如果没有其他解决方案,我可能必须做一个重要的重构。 I am hoping that I can set the sequence once and there is a copy in place/ repeating fill / bitwise operation to repeat the initial byte sequence. 我希望我可以设置一次序列,并且有一个副本/重复填充/按位操作来重复初始字节序列。

Edit simplified the example input 编辑简化了示例输入

A fast method to fill an array with a repeated sequence, is to double up length of buffer for each iteration using the copyWithin() method of the typed array. 一种用重复序列填充数组的快速方法是使用类型化数组的copyWithin()方法为每次迭代加倍缓冲区长度。 You could use set() as well by creating a different view for the same underlying ArrayBuffer , but it's simpler to use the former for this purpose. 您还可以通过为相同的基础ArrayBuffer创建一个不同的视图来使用set() ,但是使用前者更容易实现此目的。

Using for example 1234 as source, the first initial iteration fill will be 1:1, or 4 indices in this case: 使用例如1234作为源,第一个初始迭代填充将为1:1,在这种情况下为4个索引:

1234

From there we will use destination buffer as source for the remaining fill, so second iteration fills 8 indices: 从那里,我们将目标缓冲区用作剩余填充的源,因此第二次迭代将填充8个索引:

12341234

Third iteration fills 16 indices: 第三次迭代填充16个索引:

1234123412341234

Fourth iteration fills 32 indices: 第四次迭代填充了32个索引:

12341234123412341234123412341234

and so forth. 等等。

If the last segment length doesn't match power of 2 you can simple do a diff between last fill and the length remaining in the buffer and use that for the last iteration. 如果最后一段的长度不等于2的幂,则可以简单地在最后一次填充和缓冲区中剩余的长度之间进行区分,并将其用于最后一次迭代。

 var srcBuffer = new Uint8Array([1,2,3,4]), // any view type will do dstBuffer = new Uint8Array(1<<14), // 16 kb len = dstBuffer.length, // important: use indices length, not byte-length sLen = srcBuffer.length, p = sLen; // set initial position = source sequence length var startTime = performance.now(); // step 1: copy source sequence to the beginning of dest. array // todo: dest. buffer might be smaller than source. Check for this here. dstBuffer.set(srcBuffer); // step 2: copy existing data doubling segment length per iteration while(p < len) { if (p + sLen > len) sLen = len - p; // if not power of 2, truncate last segment dstBuffer.copyWithin(p, 0, sLen); // internal copy p += sLen; // add current length to offset sLen <<= 1; // double length for next segment } var time = performance.now() - startTime; console.log("done", time + "ms"); console.log(dstBuffer); 

If the array is very long it will obviously take some time regardless. 如果数组很长,则无论如何显然会花费一些时间。 In those cases you could consider using a Web Worker with the new SharedArrayBuffer so that you can do the copying in a different process and not have to copy or transfer the data to and from. 在这些情况下,您可以考虑将Web Worker与新的SharedArrayBuffer一起使用,以便可以在不同的过程中进行复制,而不必在数据之间SharedArrayBuffer复制或传输数据。 The gain from this is merely that the main thread is not blocked with little overhead dealing with the buffer as the internals of copyWithin() is relative optimal for its purpose already. 从中获得的好处仅仅是,主线程不会因为处理缓冲区而copyWithin()很少的开销就被阻塞了,因为copyWithin()的内部对于它的目的已经是相对最佳的。 The cons are the async aspect combined with the overhead from the event system (eg: it depends if this is useful). 缺点是异步方面,再加上事件系统的开销(例如:这取决于是否有用)。

A different approach is to use WebAssembly where you write the buffer fill code in C/C++, compile and expose methods to take source and destination buffers, then call that from JavaScript. 另一种不同的方法是使用WebAssembly ,在其中以C / C ++编写缓冲区填充代码,编译并公开方法以获取源缓冲区和目标缓冲区,然后从JavaScript调用该方法。 I don't have any example for this case. 对于这种情况,我没有任何示例。

In both of these latter cases you will run into compatibility issues with (not that much) older browsers. 在这两种情况下,您都会遇到与(不是那么多)旧版浏览器的兼容性问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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