javascript循环(for语句)在21亿次迭代后变慢?
javascript loop (for statement) slows down after 2.1 billion iteration?
我试图对 javascript 和 .net 核心进行基准测试,以便选择一个服务器端框架来提供一些需要迭代大型数组的特定 restful 服务(约21亿)。在处理一个简单的代码时,我意识到节点在特定的数字迭代后有奇怪的行为。我在多个平台上重复并达到相同的结果。经过测试的平台是:
- macOS Catalina (nodeJS v.12.18) 英特尔酷睿 i9 4ghz 6 核
- linux centos 7 (nodeJS v.12.18) vm intel core i9 4ghz 2 core
- google chrome 版本 84.0.4147.105(正式版)(64 位)
- Mozilla 火狐 78.2 版
running video shows surprisingly increase process time about two times from 300ms to 600ms
示例代码:
1。节点:
var cnt = 0;
var logPeriod=100000000;
var max=10000000000;
for (let i = 0; i < max; i++) {
if (i % logPeriod === 0) {
// var end = Date.now();
if (i !== 0) {
console.timeEnd(cnt*logPeriod, i);
cnt++;
}
console.time(cnt*logPeriod);
}
}
2.browser
<!DOCTYPE html>
<html>
<head>
<script>
function doloop() {
var cnt = 0;
var logPeriod = 100000000;
var max = 10000000000;
for (let i = 0; i < max; i++) {
if (i % logPeriod === 0) {
// var end = Date.now();
if (i !== 0) {
console.timeEnd(cnt * logPeriod, i);
cnt++;
}
console.time(cnt * logPeriod);
}
}
}
</script>
</head>
<body>
<button onclick="doloop()">doloop</button>
</body>
</html>
这里是 V8 开发人员。
V8 的优化编译器生成的代码尽可能使用纯 32 位整数作为数字。一旦一个数字超过 int32 范围(或精度要求,即当它需要保存小数值时),那么这种优化代码将被丢弃(或者一开始就不会生成)并使用 64 位双精度数代替,因为 JavaScript 规格要求。算术运算(甚至像 i++
这样简单的运算)在 64 位双精度数上比在 32 位整数上慢,这正是硬件所做的。
就行为而言,这种内部差异是不可观察的:数字总是表现得就好像它们是 64 位双精度数。但这并不意味着引擎实际上总是在引擎盖下使用 64 位双精度数:正如您在此处看到的那样,当引擎可以在内部使用 32 位整数时,会有显着的性能优势。
choose [JavaScript or .net for] restful services which needed to iterate large arrays(about 2.1 billion)
这是一个简单的决定:使用 .net。 V8(以及 Node)不允许您创建包含 21 亿个元素的数组,因为 per-object 大小限制远低于此。当然,var a = new Array(2_100_000_000)
会很好地评估,但那是因为它实际上并没有分配所有的内存。开始填充元素并观察它在一段时间后崩溃:-)
如果您的实际阵列毕竟不会那么大,那么请定义一个更接近您实际工作负载的基准,因为它的结果将更具代表性,因此对您的 decision-making 更有用。
我试图对 javascript 和 .net 核心进行基准测试,以便选择一个服务器端框架来提供一些需要迭代大型数组的特定 restful 服务(约21亿)。在处理一个简单的代码时,我意识到节点在特定的数字迭代后有奇怪的行为。我在多个平台上重复并达到相同的结果。经过测试的平台是:
- macOS Catalina (nodeJS v.12.18) 英特尔酷睿 i9 4ghz 6 核
- linux centos 7 (nodeJS v.12.18) vm intel core i9 4ghz 2 core
- google chrome 版本 84.0.4147.105(正式版)(64 位)
- Mozilla 火狐 78.2 版
running video shows surprisingly increase process time about two times from 300ms to 600ms
示例代码:
1。节点:
var cnt = 0;
var logPeriod=100000000;
var max=10000000000;
for (let i = 0; i < max; i++) {
if (i % logPeriod === 0) {
// var end = Date.now();
if (i !== 0) {
console.timeEnd(cnt*logPeriod, i);
cnt++;
}
console.time(cnt*logPeriod);
}
}
2.browser
<!DOCTYPE html>
<html>
<head>
<script>
function doloop() {
var cnt = 0;
var logPeriod = 100000000;
var max = 10000000000;
for (let i = 0; i < max; i++) {
if (i % logPeriod === 0) {
// var end = Date.now();
if (i !== 0) {
console.timeEnd(cnt * logPeriod, i);
cnt++;
}
console.time(cnt * logPeriod);
}
}
}
</script>
</head>
<body>
<button onclick="doloop()">doloop</button>
</body>
</html>
这里是 V8 开发人员。
V8 的优化编译器生成的代码尽可能使用纯 32 位整数作为数字。一旦一个数字超过 int32 范围(或精度要求,即当它需要保存小数值时),那么这种优化代码将被丢弃(或者一开始就不会生成)并使用 64 位双精度数代替,因为 JavaScript 规格要求。算术运算(甚至像 i++
这样简单的运算)在 64 位双精度数上比在 32 位整数上慢,这正是硬件所做的。
就行为而言,这种内部差异是不可观察的:数字总是表现得就好像它们是 64 位双精度数。但这并不意味着引擎实际上总是在引擎盖下使用 64 位双精度数:正如您在此处看到的那样,当引擎可以在内部使用 32 位整数时,会有显着的性能优势。
choose [JavaScript or .net for] restful services which needed to iterate large arrays(about 2.1 billion)
这是一个简单的决定:使用 .net。 V8(以及 Node)不允许您创建包含 21 亿个元素的数组,因为 per-object 大小限制远低于此。当然,var a = new Array(2_100_000_000)
会很好地评估,但那是因为它实际上并没有分配所有的内存。开始填充元素并观察它在一段时间后崩溃:-)
如果您的实际阵列毕竟不会那么大,那么请定义一个更接近您实际工作负载的基准,因为它的结果将更具代表性,因此对您的 decision-making 更有用。