我一直在尝试Node.JS和C++插件,发现在使用C++插件时填充Int32Array要比直接在Node.JS/JavaScript中填充慢得多。
Node.JS:133~ms
C++:1103~ms
有人知道为什么会这样吗?我的测试代码由一个相当大的数组和包含if语句的for循环组成。
我怀疑我在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++;
}
}
}
EDIT:补充一下,我在C++代码中使用的函数是V8函数,不是我自己定义的。有没有其他方法可以在不使用Int32Array的情况下设置值?
使用C最大化类型化阵列性能++
我一点也不惊讶这写得很慢,但你可以做很多事情来加快速度。关键的见解是,当在节点中处理JavaScript类型的数组时,您可以访问内存缓冲区并直接对其进行操作。
缓慢的主要来源
尽管在处理普通JavaScript数组/对象时,以下是必要的
整数::新建(隔离,值)
和
testArray->设置(值)
例如,下面的行
testArray->Set(i, Integer::New(isolate, 0));
创建一个新的Number对象,将整数0转换为双精度,因为所有JavaScript数字都是双精度,用Number调用Set,然后将双精度转换回整数,因为它将值存储在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);
}
一些测量
用上面的替换会让事情变得更快,但要快多少还需要测试。可以克隆以下包,运行时(使用节点0.125)会产生以下
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中大约需要60毫秒,在C++模块中大约需要80毫秒。但这意味着剩下的时间是在循环中花费的时间,在C++中大约为60毫秒,在Javascript中大约为110毫秒。因此,对于主要是循环和使用直接缓冲区访问的计算的操作,C++是首选。