在填充Int32Array时,Node.JS的性能与本机C++插件相比



我一直在尝试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++是首选。

相关内容

最新更新