- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在尝试为自己构建一个 WebGL 3D 库时(主要是学习目的),我遵循了从各种来源找到的文档,这些文档指出 TypedArray
函数 set()
(专门针对 Float32Array
),在 C 中应该“和”memcpy 一样快(显然是开玩笑),根据 html5rocks 字面意思是最快的.看起来似乎是正确的(在 javascript 中没有循环设置,消失在一些超快类型的数组中,纯 C 废话,等等)。
我看了一下 glMatrix (顺便说一句,干得好!),并注意到他(作者)说他展开了所有的循环以提高速度。这显然是一个 javascript 大师通常会以尽可能快的速度做的事情,但是,根据我之前的阅读,我认为我对这个库有 1-up,具体来说,他创建了他的库,使其可以同时使用数组和类型数组,因此我认为使用 set()
可以获得更快的速度,因为我只对保留 TypedArray
类型感兴趣。
为了检验我的理论,我设置了这个 jsperf .不仅 set()
相对缺乏速度,而且我尝试过的所有其他技术(在 jsperf 中)都比它好。这是迄今为止最慢的。
最后,我的问题是:为什么?理论上我可以理解一个循环展开在 spidermonkey 或 chrome V8 js 引擎中变得高度优化,但是输给一个 for 循环似乎很荒谬(jsperf 中的 copy2),特别是如果它的意图在理论上是为了加速复制,因为原始连续内存数据类型 (TypedArray
)。无论哪种方式,感觉 set()
函数都被破坏了。
这是我的代码吗?我的浏览器? (我使用的是 Firefox 24)还是我缺少其他一些优化理论?任何有助于理解与我的想法和理解相反的结果的帮助都会非常有帮助。
最佳答案
这是一个老问题,但如果您有特定需要优化一些性能不佳的代码,则有理由使用 TypedArray
。了解 JavaScript 中的 TypedArray
对象的重要一点是,它们是 View ,表示 ArrayBuffer< 内的字节范围/
。底层 ArrayBuffer
实际上表示要操作的连续二进制数据 block ,但我们需要一个 View 才能访问和操作该二进制数据的窗口。
同一 ArrayBuffer
中的独立(甚至重叠)范围可以被多个不同的 TypedArray
对象查看。当您有两个共享相同 ArrayBuffer
的 TypedArray
对象时,set
操作非常快。这是因为机器正在使用连续的内存块。
这是一个例子。我们将创建一个 32 字节的 ArrayBuffer
,一个长度为 16 的 Uint8Array
代表缓冲区的前 16 个字节,另一个长度为 16 的 Uint8Array
表示最后 16 个字节:
var buffer = new ArrayBuffer(32);
var array1 = new Uint8Array(buffer, 0, 16);
var array2 = new Uint8Array(buffer, 16, 16);
现在我们可以在缓冲区的前半部分初始化一些值:
for (var i = 0; i < 16; i++) array1[i] = i;
console.log(array1); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
console.log(array2); // [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
然后非常有效地将这 8 个字节复制到缓冲区的后半部分:
array2.set(array1);
console.log(array1); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
console.log(array2); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
我们可以通过用另一个 View 查看缓冲区来确认这两个数组实际上共享同一个缓冲区。例如,我们可以使用长度为 8 的 Uint32Array
,它跨越缓冲区的整个 32 字节:
var array3 = new Uint32Array(buffer)
console.log(array3); // [50462976, 117835012, 185207048, 252579084,
// 50462976, 117835012, 185207048, 252579084]
我修改了一个 JSPerf 测试,我发现它展示了在同一缓冲区上复制的巨大性能提升:
http://jsperf.com/typedarray-set-vs-loop/3
我们在 Chrome 和 Firefox 上的性能提高了一个数量级,甚至比采用双倍长度的普通数组并将前半部分复制到后半部分要快得多。但是我们必须在这里考虑周期/内存权衡。只要我们有对 ArrayBuffer
的任何单个 View 的引用,缓冲区的其余数据就不会被垃圾收集。一个ArrayBuffer.transfer
函数是为 ES7 Harmony 提出的,它可以解决这个问题,让我们无需等待垃圾收集器即可显式释放内存,以及无需复制即可动态增长 ArrayBuffer
的能力。
关于javascript - TypedArray 集合与展开循环 (Javascript),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19553448/
C# 有一个高性能的数组复制函数来复制数组就地: Array.Copy(source, destination, length) 它比手动操作更快,即: for (var i = 0; i < len
我正在学习泛型,并用编译器解决了这个问题: type FloatArray = Float32Array | Float64Array; type IntegerArray = | Int8Arr
查看 TypedArray ( link ) 的源代码,我似乎无法弄清楚这两种方法之间的区别。 getInt() 与getInteger() 基本相同,只是在最后加了一个我看不懂的小东西。谁能给我解释
sdk更新到Android 5.0后方法消失了TextView.getTextColor(Context context, TypedArray typedArray, int defStyle) .
为什么 TypedArray 不如常规数组快?我想存储一些预先计算的整数值,并且需要尽可能快地访问数组。 http://jsperf.com/array-access-speed-2/2 准备代码:
我正在尝试使用 WebGL,并希望将一些不同的类型混合到一个字节缓冲区中。我知道 TypedArrays 可以达到这个目的,但不清楚我是否可以与它们混合类型(OpenGL 顶点数据通常是与无符号字节或
我正在学习自定义组件,我在使用自定义 xml 属性时遇到了一些问题。 我的自定义组件扩展了 LinearLayout 并在构造函数中(public Custom(Context context, At
This answer告诉我调用 recycle() TypedArray 的方法允许它被垃圾收集。我的问题是为什么 TypedArray 特别需要一种方法来对其进行垃圾回收?为什么它不能像普通对象一
在 Chrome(可能还有其他浏览器)中,当我将值存储到超出其范围的 TypedArray 时,它会被 chop : const arr = new Uint16Array(1); arr[0] =
我试图用这个简单的代码片段将 typedArray 拆分成更小的 block : const buf = new Uint8Array([0x02, 0x00, 0x07, 0x63, 0x6f, 0
我有一个源 Float32Array,我从中创建了一个辅助 Float32Array。我有一个值序列 model,我想将其作为重复序列复制到辅助 Float32Array 中。我目前正在使用反向 wh
要测试一个对象是否是一个数组,有一个方法—— const myarray = [1,2,3,4]; Array.isArray(myarray); //returns true 对于类型化数组(例如,
在尝试为自己构建一个 WebGL 3D 库时(主要是学习目的),我遵循了从各种来源找到的文档,这些文档指出 TypedArray 函数 set() (专门针对 Float32Array ),在 C 中
我有一个 typedArray,其中包含我想在 ListView 中使用的图标。当我尝试在 for 循环 this.navDrawerIcons 中引用 typedArray 中包含的元素时如下所示,
给定像 Uint8Array 这样的类型化数组,似乎有两种方法可以通过 worker 传输它们。 选项 1 直接发送缓冲区并在接收端进行转换: 发件人:postMessage({fooBuffer:
根据the documentation on the Uint8ClampedArray , The Uint8ClampedArray typed array represents an array
我在 android 自定义 TextView 中设置了多个标志属性,如何使用 TypedArray 恢复这些属性 最佳答案 attrs.xml
我从使用 android L 预览版的设备收到一些崩溃报告,问题是 Caused by: java.lang.RuntimeException: [17, ...... ] recycled twic
我正在尝试编写一个函数,通过将任意 TypedArray 作为输入来扩展/缩小 TypedArray,并返回一个具有不同大小的新的相同类型的 TypedArray,并将原始元素复制到其中。 例如,当您
我正在通过 XHR 加载远程资源并将其接收为 arrayBuffers 。底层数据为float32依赖。我需要对这些数组缓冲区进行一些进一步的操作,例如串联和合并。对于这些操作,我正在尝试 buffe
我是一名优秀的程序员,十分优秀!