javascript循环(for语句)在21亿次迭代后会变慢吗?

javascript循环(for语句)在21亿次迭代后会变慢吗?,javascript,for-loop,v8,slowdown,Javascript,For Loop,V8,Slowdown,我试图对javascript和.net core进行基准测试,以便选择一个服务器端框架来提供一些特定的restful服务,这些服务需要迭代大型数组(大约21亿)。在编写一个简单的代码时,我意识到节点在经过特定次数的迭代后会有奇怪的行为。我在多个平台上重复了一遍,得到了相同的结果。测试平台包括: macOS catalina(nodeJS v.12.18)intel core i9 4ghz 6 core linux centos 7(nodeJS v.12.18)vm intel core i

我试图对javascript和.net core进行基准测试,以便选择一个服务器端框架来提供一些特定的restful服务,这些服务需要迭代大型数组(大约21亿)。在编写一个简单的代码时,我意识到节点在经过特定次数的迭代后会有奇怪的行为。我在多个平台上重复了一遍,得到了相同的结果。测试平台包括:

  • macOS catalina(nodeJS v.12.18)intel core i9 4ghz 6 core
  • linux centos 7(nodeJS v.12.18)vm intel core i9 4ghz 2 core
  • google chrome版本84.0.4147.105(官方版本)(64位)
  • Mozilla firefox版本78.2

示例代码: 1.nodejs:
var cnt=0;
var logPeriod=100000000;
var max=1000000000;
for(设i=0;i
这里是V8开发者

V8的优化编译器生成的代码尽可能长地使用纯32位整数表示数字。一旦一个数字超过了int32范围(或精度要求,即当它需要保留小数时),那么这种优化的代码就会被丢弃(或者根本就不会生成),而使用64位双精度,正如JavaScript规范所要求的那样。算术运算(即使是像
i++
这样简单的运算)在64位双精度上比在32位整数上慢,这正是硬件所做的

就行为而言,这种内部差异是无法观察到的:数字的行为总是好像它们是64位的双倍。但这并不意味着引擎实际上总是在引擎盖下使用64位双精度:正如您在这里所看到的,当引擎可以在内部使用32位整数时,会有显著的性能优势

选择[JavaScript或.net for]restful服务,这需要迭代大型数组(约21亿个)

这是一个简单的决定:使用.net。V8(以及节点)不允许创建包含21亿个元素的数组,因为每个对象的大小限制远远低于此限制。当然,
var a=newarray(2_100_000_000)
的计算结果很好,但这是因为它实际上并没有分配所有内存。开始填充元素并观察它在一段时间后崩溃:-)


如果您的实际阵列毕竟没有那么大,那么请定义一个更接近您实际工作负载的基准,因为它的结果将更具代表性,因此对您的决策更有用。

可能
cnt*logPeriod
最终超出了真正的整数范围(31位)还有更大整数的浮点表示,因此速度会变慢。等等,您的应用程序确实有一个用例,您的服务器需要迭代21亿个条目的数组?好的。对然而,在幕后实现“引擎”时,为了提高效率,在适当的位范围内使用范数类型的整数。这取决于引擎的实现。因此,这很可能是OP环境中速度减慢的原因。@GetSet:YouTheSpot;除了它不仅是
cnt*logPeriod
而且
i
本身超出了int32范围之外。@AhadRafatTalebi:这是意料之中的。操作系统和CPU并不重要,因为浮点运算总是比整数运算慢;只有差异的大小可能取决于硬件(我在我的机器上看到大约4倍:120毫秒对540毫秒)。它是否是64位操作系统也无关紧要:“内部使用int32”技巧不能扩展到int64,因为可能的int32值是双值的子集,但int64值不是:它们太精确了,因此如果引擎使用它们,那将是一个bug。这很棘手:-)非常好地描述了v8结构。您是对的,但作为最后一次尝试,您认为有可能在这种情况下使用新功能吗?如何增加每个对象的大小限制<代码>节点--堆栈大小=1000000000000000--最大旧空间大小=65536-p“数组(2_100_000_000)。填充(null)。长度“
没有帮助。我需要定制版本吗?我应该更改哪个常量?有趣的是,QuickJS在默认情况下没有限制:
qjs-e“Array(2_100_000_000)。fill(null)”
在消耗了31.3G内存后成功。@AhadRafatTalebi:我不明白您到底想在这里使用BigInts什么;对于循环变量
i
?你当然可以使用它们;作为一项新功能,它们还没有收到像数字那样多的优化效果,所以现在重BigInt的代码往往比基于数字的代码慢。@AlanLiang:您不能增加V8的每对象大小限制。预计不同的发动机有不同的限制。它们可能是自我强加的任意限制,也可能来自内部实现设计选择。V8仅使用30位表示对象的大小,因此每个对象必须适合1G。我们更喜欢这种方式,因为(1)使用更多的位会增加元数据开销,(2)在大多数情况下,作为用户,您甚至不希望单个对象使用更多的内存。FWIW,射线会变大。