下面这段性能测试很有启发性,数据的初始化准备如下:
// setup:
const KB = 1024
const MB = 1024 * KB
// These are approximate sizes to fit in those caches. If you don't get the
// same results on your machine, it might be because your sizes differ.
const L1 = 256 * KB
const L2 = 5 * MB
const L3 = 18 * MB
const RAM = 32 * MB
// We'll be accessing the same buffer for all test cases, but we'll
// only be accessing the first 0 to `L1` entries in the first case,
// 0 to `L2` in the second, etc.
const buffer = new Int8Array(RAM)
buffer.fill(42)
const random = (max) => Math.floor(Math.random() * max)
简单的说,就是准备了一个大数组buffer,然后随机访问其中的某个元素。
分为四种情况,每种情况只是随机的范围有区别:
// 1. L1
let r = 0; for (let i = 0; i < 100000; i++) { r += buffer[random(L1)] }
// 2. L2
let r = 0; for (let i = 0; i < 100000; i++) { r += buffer[random(L2)] }
// 3. L3
let r = 0; for (let i = 0; i < 100000; i++) { r += buffer[random(L3)] }
// 4. RAM
let r = 0; for (let i = 0; i < 100000; i++) { r += buffer[random(RAM)] }
性能结果如下图:
可以看出,如果限制数组的访问范围在很小的区域,js的执行性能会好很多。
这个原因也不难理解,因为js引擎会利用缓存技术,每次缓存加载数据,都不简单的加载目标数据,而是会连带目标数据周边的数据一同加载。如果下一次访问的数据恰好在缓存中,那么缓存命中,避免了额外的IO操作,性能就会得到提升。
现在计算机都有多级缓存(L1/L2/L3),数据集合越小,在前级命中的概率越高,性能也就越好。