使用数组时,Javascript 向后循环变慢?
Posted
技术标签:
【中文标题】使用数组时,Javascript 向后循环变慢?【英文标题】:Javascript backwards loop slower when working with arrays? 【发布时间】:2015-10-31 16:25:53 【问题描述】:我们中的许多人可能已经知道这一点:
var list = ...
var index = list.length
while( index-- )
// do something
据说这是在 javascript 中执行循环的最快方法,因为您避免了额外的测试。到目前为止,在过去的几年中,我在处理速度很重要但顺序并不重要的数据时使用了这种技术。
但现在我偶然发现一篇文章说处理数组时实际上速度较慢。
这使您避免了额外的测试(与标准相比 环形)。但你知道吗?这将比使用 正确的顺序。因为世界上所有的 CPU 缓存都期望处理 要“直接”,您将一次又一次地缓存未命中,并且 2X 当你幸运的时候,你会慢下来。
所以不要向后循环,除非你有充分的理由这样做。
来源:https://gamealchemist.wordpress.com/2013/05/01/lets-get-those-javascript-arrays-to-work-fast/
现在我很好奇!我只有有限的可能性来测试这些东西,而且我发现的所有其他地方仍然说反向循环是最快的方法(甚至是 *** 上的多个答案)。 在处理(可能很大)数组时真的是这样吗?
在过早的优化答案弹出之前(就像这类问题经常发生的那样):这主要是出于好奇,是的,在游戏之类的事情中,性能很重要!
关于 jsperf: 到目前为止,jsperf 似乎暗示向后循环更快(我现在无法检查测试,因为它不会在任何 atm 上加载结果 - 所以我我在回忆我之前看到的)。这就是这个问题的来源:这两条信息相互矛盾——至少如果那篇文章中所说的是真的!那么到底什么是“正确”呢?
【问题讨论】:
你为什么不在你关心的浏览器中用 jsperf 测试它(需要几分钟才能得到你的第一个结果)?所有性能问题都必须通过在您关心的环境中进行测试来回答。发布此问题而您自己没有进行任何测试似乎表明您只是希望其他人为您进行测试。 与缓存未命中相关的事实是正确的。 CPU 期望数组按顺序遍历。 另外,由于 JS 引擎会定期添加性能增强功能,因此完全有可能某些或许多浏览器已经为典型的数组迭代for
循环添加了优化以加快速度。你几年前读过的东西,今天可能不再适用。
@jfriend00 是的,但这也是问题所在(也是这个问题的原因):jsperf 似乎暗示向后循环更快(这些年来我在这里看到了一些测试)。所以 jsperf 实际上与此相矛盾 - 但也许情况也是如此,因为这些测试过于专注于一件事?我真的很想知道“因为世界上所有的 CPU 缓存都希望处理是‘直接的’,所以你会有缓存未命中……”这个论点是否基于现实——因为如果是这样的话,反向循环理论上应该慢一点,对吧?
如果你在几个浏览器中有当前的 jsperf 性能数据,那就贴出来吧。如果没有一些性能数据,这个问题真的毫无意义。在进行测量以了解当前的事态之前,没有什么有用的讨论。通过对事物进行理论化,您无法弄清楚哪件事会更快。你测量。您可以尝试通过理论化来解释测量,但不能反过来。
【参考方案1】:
该论点中的推理是无效的。 CPU 缓存为有序的内存访问提供了好处,因为它们会缓存内存块,如果您按顺序浏览内存,那么您将连续多次访问同一个块,而不必每次都加载一个块。
但是,无论您是在这样的线性进程中前进还是后退,这与是否适用没有区别。
可能有许多不同的因素会影响此类替代方案的相对性能(尤其是如果引擎试图优化特定的常见模式,这可能意味着那些看起来比竞争对手做得更多的工作实际上做得更少)。这些因素也可能因平台而异。
但是这个期望向前访问击败向后访问的特殊原因并没有成功。
【讨论】:
似乎是指cache prefetching,它试图在缓存未命中发生之前获取下一个缓存块。 @Bergi 当不尝试更奇特的东西时,我曾认为这是双向的。毕竟,用于堆栈的上下内存是一种特别常见的模式。 是的,你需要有一个非常愚蠢的预测器,我只想提一下,推理并非完全无效。但我完全同意“可能有很多不同的因素在起作用……”以上是关于使用数组时,Javascript 向后循环变慢?的主要内容,如果未能解决你的问题,请参考以下文章
带有嵌套for循环的Javascript多维数组-无法正常工作