代码之家  ›  专栏  ›  技术社区  ›  kevzettler

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

  •  1
  • kevzettler  · 技术社区  · 8 年前

    我有消息来源 Float32Array 浮点32阵列 从…起我有一系列的价值观 model 浮点32阵列 . 我目前正在使用反向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];
    }
    

    不幸地 n

    编辑

    1 回复  |  直到 8 年前
        1
  •  3
  •   user1693593 user1693593    8 年前

    用重复序列填充数组的一种快速方法是使用 copyWithin() set() 也可以为相同的底层创建不同的视图 ArrayBuffer ,但将前者用于此目的更简单。

    1234 作为源,第一次初始迭代填充将为1:1,或在这种情况下为4个索引:

    1234
    

    在那里,我们将使用目标缓冲区作为剩余填充的源,因此第二次迭代填充8个索引:

    12341234
    

    1234123412341234
    

    第四次迭代填充32个索引:

    12341234123412341234123412341234
    

    等等

    如果最后一段长度与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);

    如果阵列很长,显然需要一些时间。在这种情况下,您可以考虑使用 Web Worker SharedArrayBuffer 这样,您就可以在不同的过程中进行复制,而不必在之间复制或传输数据。这样做的好处仅仅是主线程没有被阻塞,将缓冲区作为 copyWithin() 就其目的而言,它已经是相对最优的。缺点是异步方面与事件系统的开销相结合(例如:这取决于这是否有用)。

    另一种方法是使用 WebAssembly

    在后两种情况下,您都会遇到与旧浏览器(不是那么多)的兼容性问题。