Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the process of cache miss analysis for JavaScript

2025-04-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

About JavaScript cache miss analysis process, many novices are not very clear about this, in order to help you solve this problem, the following editor will explain for you in detail, people with this need can come to learn, I hope you can gain something.

Introduction

JavaScript is a very high-level language, so you don't have to think too much about the way the data is stored in memory when developing with JavaScript. In this article, we will explore how data is stored in memory and how the way data is distributed and accessed in JavaScript will affect CPU and memory performance.

Romantic triangle

When the computer needs to perform some computing tasks, the computer processing unit (CPU) needs data to be processed, so, according to the task at hand, it sends a request to memory to obtain the data to be processed through the bus, like the following:

This is our romantic triangle.

CPU- > bus-> memory

The romantic triangle needs a fourth element to keep it stable.

Because CPU is much faster than memory, processing from CPU- > bus-> memory-> bus-> CPU wastes a lot of computing time, because CPU is idle when looking for memory and cannot perform other operations.

The emergence of caching effectively alleviates this problem. We will not discuss the technical details and types of caching in detail in this article, we just need to know that caching can be used as an internal storage space for CPU.

When CPU receives the command to run, it first searches the cache for the target data, and if it does not find the target data, it initiates the request through the bus.

The bus then adds a portion of the requested data to memory and stores it in a cache for CPU to quickly call.

In this way, CPU can process the data efficiently without wasting time waiting for memory to return.

Cached references can also cause new problems

Based on the above architecture, we may have an error called "cache miss" when dealing with large amounts of data.

Cache misses means that during the calculation, CPU finds that there is no necessary data in the cache and therefore needs to request this data through a regular channel (that is, known slow memory).

The figure above is a good example. In the processing group, the cache misses because the calculated data exceeds the cache limit.

But what does this have to do with me as a JavaScript programmer?

Good question, for the most part, we JavaScript developers don't have to care about it. But as more and more data flows into Node.js servers and even rich clients, it is easy to encounter cache misses when using JavaScript to traverse large datasets.

A classic example.

Next, let's take an example as an example.

This is a class called Boom:

Class Boom {constructor (id) {this.id = id;} setPosition (x, y) {this.x = x; this.y = y;}}

This class (Boom) has only three attributes: id,x and y.

Now, let's create a method to populate x and y.

Let's build the settings:

Const ROWS = 1000; const COLS = 1000; const repeats = 100; const arr = new Array (ROWS * COLS) .fill (0) .map ((a, I) = > new Boom (I))

Now, we will use this setting in one method:

Function localAccess () {for (let I = 0; I)

< ROWS; i++) { for (let j = 0; j < COLS; j++) { arr[i * ROWS + j].x = 0; } } } 本地访问的作用是线性遍历数组并将x设置为0。 如果我们重复执行此功能100次(请查看设置中的重复常数),则可以测量运行时间: function repeat(cb, type) { console.log(`%c Started data ${type}`, 'color: red'); const start = performance.now(); for (let i = 0; i < repeats; i++) { cb(); } const end = performance.now(); console.log('Finished data locality test run in ', ((end - start) / 1000).toFixed(4), ' seconds'); return end - start; } repeat(localAccess, 'Local'); 日志输出是这样的: 丢失缓存要付出的代价 现在,根据上面的了解,如果我们处理迭代过程中距离较远的数据,则会导致缓存丢失。远处的数据是不在相邻索引中的数据,如下所示: function farAccess() { for (let i = 0; i < COLS; i++) { for (let j = 0; j < ROWS; j++) { arr[j * ROWS + i].x = 0; } } } 在这里发生的是,在每次迭代中,我们都处理上次迭代距ROWS的索引。因此,如果ROWS为1000(在我们的例子中),我们将得到以下迭代:[0,1000,2000,…,1,1001,2001,…]。 让我们将其添加到速度测试中: repeat(localAccess, 'Local'); setTimeout(() =>

{repeat (farAccess, 'Non Local');}, 2000)

This is the end result:

The speed of non-local iteration is almost four times slower. With the increase of the amount of data, this difference will become bigger and bigger. This occurs because the cache misses and CPU is idle.

So what is the price you have to pay? It all depends on the size of your data.

Well, I swear I'll never do that!

You may not usually think so, but in some cases, you may want to use nonlinearity (for example, 1mem2pencils 3pencils 4pens 5) or non-accidental. For example (for (let I = 0; I)

< n; i+=1000)) 例如,您从服务或数据库中获取数据,并需要通过某种复杂的逻辑对数据进行排序或过滤。这可能导致访问数据的方式与farAccess函数中显示的方式类似。 如下所示: 查看上图,我们看到了存储在内存中的数据(顶部灰色条)。在下面,我们看到了当数据从服务器到达时创建的数组。最后,我们看到排序后的数组,其中包含对存储在内存中各个位置的对象的引用。 这样,对排序后的数组进行迭代可能会导致在上面的示例中看到的多个缓存未命中。 请注意,此示例适用于小型阵列。高速缓存未命中与更大的数据有关。 在当今世界中,您需要在前端使用精美的动画,并且可以在后端(无服务器或其他服务器)中为CPU的每毫秒时间计费(这很关键)。 不好了!都没了!!! 并不是,有多种解决方案可以解决此问题,现在您已经知道造成性能下降的原因,您可以自己考虑解决方案。比如只需要将处理在一起的数据更紧密地存储在内存中。 这种技术称为数据局部性设计模式。 让我们继续我们的例子。假设在我们的应用程序中,最常见的过程是使用farAccess函数中显示的逻辑来遍历数据。我们希望对数据进行优化,以使其在最常见的for循环中快速运行。我们将像这样排列相同的数据: const diffArr = new Array(ROWS * COLS).fill(0); for (let col = 0; col < COLS; col++) { for (let row = 0; row < ROWS; row++) { diffArr[row * ROWS + col] = arr[col * COLS + row]; } } 所以现在在diffArr中,原始数组中索引为[0,1,2,…]的对象现在被设置为[0,1000,2000,…,1,1001,2001,…,2, 1002,2002,…]。数字表示对象的索引。这模拟了对数组进行排序的方法,这是实现数据局部性设计模式的一种方法。 为了方便测试,我们将稍微更改farAccess函数以获得一个自定义数组: function farAccess(array) { let data = arr; if (array) { data = array; } for (let i = 0; i < COLS; i++) { for (let j = 0; j < ROWS; j++) { data[j * ROWS + i].x = 0; } } } 现在将场景添加到我们的测试中: repeat(localAccess, 'Local'); setTimeout(() =>

{repeat (farAccess, 'Non Local') setTimeout (() = > {repeat (()) = > farAccess (diffArr),' Non Local Sorted')}, 2000);}, 2000)

We run it, and we get:

We have optimized the data to accommodate the more common ways we need to view it.

Is it helpful for you to read the above content? If you want to know more about the relevant knowledge or read more related articles, please follow the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report