为什么我的 C++ 插件中的 Google V8 JavaScript 引擎的运行速度比在 Node.JS 中慢很多?
我尝试编写一些愚蠢的简单代码来在 JavaScript 中生成素数,并通过我的 C++ 插件在 V8 中运行它,并直接在 Node.JS 中运行。
我很震惊,因为它们应该使用相同的 JavaScript 引擎并且都执行了相同的代码(时间以毫秒为单位,越少越好):
V8 in Node.JS: 495517
V8 in Node.JS C++ Addon: 623598
这里是运行相同 JavaScript 代码的 JavaScript 模块和 C++ 插件的源代码(我认为问题不在互操作中,因为时间测量直接在 JS 中工作):
index.js:
var jsInNodeJsPrimeGeneratorBenchmark = require("./javascript.js");
var jsInNativePrimeGeneratorBenchmark = require("./native");
console.log("V8 in Node.JS: ", jsInNodeJsPrimeGeneratorBenchmark.primeGeneratorBenchmark());
console.log("V8 in Node.JS C++ Addon: ", jsInNativePrimeGeneratorBenchmark.primeGeneratorBenchmark());
javascript.js:
function primeGeneratorBenchmark() {
var result, primeNumberCounter, i, j, isPrime, start, end;
i = 3;
primeNumberCounter = 1;
start = Date.now();
while (primeNumberCounter < 100000) {
isPrime = true;
for (j = 2; j < i; j++) {
if (i % j === 0) {
isPrime = false;
break;
}
}
if (isPrime) {
result = i;
primeNumberCounter++;
}
i++;
}
end = Date.now();
return end - start;
}
exports.primeGeneratorBenchmark = primeGeneratorBenchmark;
native.cpp:
#include <node.h>
v8::Handle<v8::Value> primeGeneratorBenchmark(const v8::Arguments &arguments);
void registerModule(v8::Handle<v8::Object> target);
v8::Handle<v8::Value> primeGeneratorBenchmark(const v8::Arguments &arguments) {
v8::HandleScope handleScope;
v8::Local<v8::Context> context = arguments.Holder()->CreationContext();
v8::Context::Scope scope(context);
const char *sourceStringC =
"var result, primeNumberCounter, i, j, isPrime, start, end, time;\n"
"i = 3;\n"
"primeNumberCounter = 1;\n"
"start = Date.now();\n"
"while (primeNumberCounter < 100000) {\n"
" isPrime = true;\n"
" for (j = 2; j < i; j++) {\n"
" if (i % j === 0) {\n"
" isPrime = false;\n"
" break;\n"
" }\n"
" }\n"
" if (isPrime) {\n"
" result = i;\n"
" primeNumberCounter++;\n"
" }\n"
" i++;\n"
"}\n"
"end = Date.now();\n"
"time = end - start;\n";
v8::Local<v8::String> sourceStringV8 = v8::String::New(sourceStringC);
v8::Local<v8::Script> script = v8::Script::Compile(sourceStringV8);
script->Run();
v8::Local<v8::Value> timeResult = v8::Context::GetCurrent()->Global()->Get(v8::String::New("time"));
return handleScope.Close(timeResult);
}
void registerModule(v8::Handle<v8::Object> target) {
target->Set(v8::String::NewSymbol("primeGeneratorBenchmark"), v8::FunctionTemplate::New(primeGeneratorBenchmark)->GetFunction());
}
NODE_MODULE(native, registerModule);
最佳答案
在 C++ 版本中,脚本源中声明的所有变量(result
、primeNumberCounter
、i
、j
, isPrime
, start
, end, time
) 是 global 因为脚本的顶级作用域是全局作用域。
为了优化编译器,很容易将局部变量分配到机器寄存器(或堆栈上的溢出槽)并跟踪它们的类型。另一方面,使用全局变量需要持续的内存访问和类型检查,因为 V8(当前)不执行寄存器提升优化。
如果您将源代码包装到立即调用的函数中,差异应该会消失。
关于javascript - 为什么 Node.JS 中的 V8 比我的原生 C++ 插件更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15393039/