我一直在尝试使用Node.JS和C ++插件,发现在使用C ++插件时填充Int32Array要慢得多,而不是在Node.JS / JavaScript中直接填充。
Node.JS:133~ms
C ++:1103~ms
有谁知道这是为什么?我的测试代码包含一个相当大的数组和 for 循环,其中包含 if 语句。
我怀疑我在C ++插件中错误地填充了数组。 (?)
JavaScript的:
var testArray = new Int32Array(36594368);
var i = 0;
for (var xi = 0; xi < 332; xi++) {
for (var yi = 0; yi < 332; yi++) {
for (var zi = 0; zi < 332; zi++) {
if ((xi + yi + zi) % 62 == 0) testArray[i] = 2;
else if (yi < 16) testArray[i] = 2;
else if (yi == 16) testArray[i] = 1;
else testArray[i] = 0;
i++;
}
}
}
C ++插件:
Local<Int32Array> testArray = Int32Array::New(ArrayBuffer::New(isolate, 4 * 36594368), 0, 36594368);
int i = 0;
for (int xi = 0; xi < 332; xi++) {
for (int yi = 0; yi < 332; yi++) {
for (int zi = 0; zi < 332; zi++) {
if ((xi + yi + zi) % 62 == 0) testArray->Set(i, Integer::New(isolate, 2));
else if (yi < 16) testArray->Set(i, Integer::New(isolate, 2));
else if (yi == 16) testArray->Set(i, Integer::New(isolate, 1));
else testArray->Set(i, Integer::New(isolate, 0));
i++;
}
}
}
编辑:添加,我在C ++代码中使用的功能是V8功能,并且我自己没有定义。有没有其他方法可以在不使用这些值的情况下在Int32Array中设置值?
答案 0 :(得分:10)
我并不感到惊讶,这写得很慢,但你可以做很多事情来加快速度。关键的见解是,当在节点中处理JavaScript类型的数组时,您可以访问内存缓冲区并直接对其进行操作。
虽然在处理普通的JavaScript数组/对象时,以下是必要的
整数::新(分离,值)
和
testArray-&gt;设置(值)
例如以下一行
testArray->Set(i, Integer::New(isolate, 0));
创建一个新的 Number 对象,将整数0转换为double,因为所有JavaScript数字都是double,使用 Number 对象调用 Set ,然后将double转换回整数,因为它将值存储在 Int32 类型的数组中,然后销毁Number对象。这发生了300万次。
但是类型化数组是不同的,调用 GetIndexedPropertiesExternalArrayData 提供对底层缓冲区的一次访问,对于 Int32Array 是 int 。这允许重写C ++函数以避免所有这些分配和强制转换:
void doMkArray(const FunctionCallbackInfo<Value> &args)
{
v8::Isolate *I = v8::Isolate::GetCurrent();
Local<Int32Array> testArray = Int32Array::New(ArrayBuffer::New(I, 4 * 36594368),0,36594368);
int *dptr = (int*)testArray->GetIndexedPropertiesExternalArrayData();
int i = 0;
for (int xi = 0; xi < 332; xi++)
{
for (int yi = 0; yi < 332; yi++)
{
for (int zi = 0; zi < 332; zi++)
{
if ((xi + yi + zi) % 62 == 0) dptr[i] = 2;
else if (yi < 16) dptr[i] = 2;
else if (yi == 16) dptr[i] = 1;
else dptr[i] = 0;
i++;
}
}
}
args.GetReturnValue().Set(testArray);
}
替换上述内容会使事情变得更快,但测试需要多快。可以克隆following package并在运行时(使用节点0.12.5)得到以下结果
Performance Tests
✓ via javascript (169ms)
✓ via c++ (141ms)
因此,单独使用C ++会更快,但也许并不是那么令人惊奇,但是如果Javascript和C ++循环(参见src)都被注释掉了,并且只包含了数组分配:
void doMkArray(const FunctionCallbackInfo<Value> &args)
{
v8::Isolate *I = v8::Isolate::GetCurrent();
Local<Int32Array> testArray = Int32Array::New(ArrayBuffer::New(I, 4
/*
...
然后时间变为
Performance Tests
✓ via javascript (62ms)
✓ via c++ (80ms)
换句话说,简单地分配数组在JavaScript中大约需要60ms,在C ++模块中需要80ms。但这意味着剩下的时间是在循环中花费的时间,在C ++中约为60ms,在Javascript中约为110ms。因此,对于主要使用直接缓冲区访问进行循环和计算的操作,首选C ++。