【问题标题】:Is cache miss possible in NodeJS and how to get it?在 NodeJS 中是否可能缓存未命中以及如何获取它?
【发布时间】:2019-10-30 18:45:33
【问题描述】:

来自Wikipedia,缓存未命中是在缓存中读取或写入一段数据的失败尝试,这会导致延迟更长的主内存访问。

但是,我不明白我们在谈论什么样的数据以及如何综合再现这些数据。根据this的回答,通过调整算法进行缓存优化,避免访问时产生数据碎片。

/* Array.prototype.flat polyfill */
Array.prototype.flat = function() {
    this.reduce((a, v) => Array.isArray(v) ? a.concat(v.flat()) : a.concat(v), []);
};
/* Cache test */
const len = 100;
const generateArr = (len) =>  {
    const mat = [...new Array(len)].map(() => 
        [...new Array(len)].map(() => Math.round(Math.random() * 10))
    );
    return new Uint8Array(mat.flat(Infinity))
};
const arr = generateArr(len)
/* {1, 2, 3, 4, 5, 6, 7, 8, 9, n} */
const testFriendly = () => {
    let total=0;    
    for (let x=0;x!=len;x+=10) {
        for (let y=0;y!=10;y++) {
            total+=arr[x+y];
        }
    }
};
/* {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 1, 11, 12, n}*/
const testUnfriendly = () => {
    let total=0;
    for (let y=0;y!=10;y++) {
        for (let x=0;x!=len;x+=10) {
            total+=arr[x+y];
        }
    }
};
const test = () => {
    console.time("Cache-friendly");
    for (let i=0; i!=7000; i++) {
        testFriendly();
    }
    console.timeEnd("Cache-friendly");
    console.time("Cache-unfriendly");
    for (let i=0; i!=7000; i++) {
        testUnfriendly();
    }
    console.timeEnd("Cache-unfriendly");
};
test()
test()
test()
test()

JIT 完成后,友好测试运行得更快,但并非总是如此。这是缓存未命中吗?

但是应用程序程序员可以在 NodeJS 平台上获得缓存未命中吗?是否有任何反模式来保证缓存未命中并防止生产代码中出现类似情况?

【问题讨论】:

  • 这不是你真正应该关心的事情。这个高度依赖处理器(环境),是NodeJS/V8团队的问题。作为一名 JS 开发人员,我假设引擎在尽可能多地利用 L 缓存方面做得最好。
  • 你能运行这些测试并平均结果吗? IE。运行这 1000 次,将时间相加,然后除以 1000?

标签: javascript node.js algorithm optimization ecmascript-6


【解决方案1】:

我们在谈论什么样的数据?

基本上所有数据

可以在三个地方存储(写入、读取)数据:

(1) 直接处理器上注册[几个字节]。

(2) RAM(前面有缓存)[几千兆/太字节]

(3) I/O(硬盘、SSD、网络适配器)[无限制]

由于您无法直接访问 (1) 和 (3),因此您的所有数据基本上都在 RAM 中。

NodeJS 中是否可能发生缓存丢失以及如何获取它?

当然。在最佳情况下,如果您使用的所有数据都被缓存,并且整个缓存都被利用,那么几 kB 存储在 L1 中,几百 kB 存储在 L2 中,几 MB 存储在 L3 中。因此,如果您使用的数据超出了这些缓存的容量,则肯定会发生缓存未命中(尽管如此,它们很可能会发生)。

JIT 完成后,友好测试运行得更快,但并非总是如此。这是缓存未命中吗?

好吧,让我们看看你正在操作的堆栈:

JavaScript <- you are here
/* gets run by */
V8 / NodeJS <- optimizations do happen
/* is written in */
C++ <- optimizations do happen, the other question is at this level
/* gets compiled to */
bytecode <- optimizations do happen
/* gets finally run on */
The Processor <- here the caches come into play

换句话说:与 C++ 问题不同,在 NodeJS 中还有另一个级别的优化。该级别可能会引入其他缓存,可能会更改数据在内存中的表示方式,或者进行其他优化。您可以分析 V8 执行的字节码,并针对它进行优化.. 但是下一个 V8 版本可能会引入另一种优化,这会使您的“优化”过时。

但是应用程序程序员可以在 NodeJS 平台上获得缓存未命中吗?

当然。在引擎盖下的某个地方,很可能,经常。但是……你能做点什么吗?不,不是。 V8 团队或 C++ 编译器实现者可以,你不能,真的。

是否有任何反模式以保证缓存未命中并防止在生产代码中出现类似情况?

是的,不要编写疯狂的代码。

估计来自Nick Craver's blog,我强烈建议阅读:)

【讨论】:

  • 那么像Uint8Array 这样的缓冲区呢?所有数据都彼此相邻放置,这应该会在迭代数据时改善缓存未命中率。
  • @dev.dmtrllv 是的,迭代连续内存(可能是底层缓冲区)是处理器的最佳优化方案(它们将内存从 RAM 预取到缓存中)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-07
  • 2021-03-08
  • 1970-01-01
  • 1970-01-01
  • 2021-04-20
  • 2021-11-14
  • 1970-01-01
相关资源
最近更新 更多