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

Joe*_*ani 12 javascript c++ performance node.js

我一直在尝试使用Node.JS和C++插件,发现在使用C++插件时填充Int32Array要慢得多,而不是在Node.JS/JavaScript中直接填充.

Node.JS:133~ms
C++:1103~ms

有人知道为什么吗?我的测试代码包含了相当大阵,并包含循环如果语句.

我怀疑我在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++;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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++;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:只是添加,我在我的C++代码中使用的函数是V8函数,并不是我自己定义的.有没有其他方法在Int32Array中设置值而不使用它们?

waT*_*eim 10

使用C++最大化Typed Array性能

我并不感到惊讶,这写得很慢,但你可以做很多事情来加速它.关键的见解是,当在节点中处理JavaScript类型的数组时,您可以访问内存缓冲区并直接对其进行操作.

缓慢的主要来源

虽然在处理普通的JavaScript数组/对象时,以下是必要的

整数::新(隔离,)

testArray-> Set(value)

例如,以下行

testArray->Set(i, Integer::New(isolate, 0));
Run Code Online (Sandbox Code Playgroud)

创建一个新的Number对象,将整数0转换为double,因为所有JavaScript数都是double,调用Set使用Number对象,然后将double转换回整数,因为它将值存储在Int32类型的数组中,然后破坏数字对象.这发生了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);
}
Run Code Online (Sandbox Code Playgroud)

一些测量

用上面的代替可以让事情变得更快,但是测试需要多快.在下面的包可以被克隆和运行时(使用节点0.12.5)结果示于下述

  Performance Tests
    ? via javascript (169ms)
    ? via c++ (141ms)
Run Code Online (Sandbox Code Playgroud)

所以单独使用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 
/*
...
Run Code Online (Sandbox Code Playgroud)

然后时间变为

  Performance Tests
    ? via javascript (62ms)
    ? via c++ (80ms)
Run Code Online (Sandbox Code Playgroud)

换句话说,简单地分配数组在JavaScript中大约需要60ms,在C++模块中需要80ms.但这意味着剩下的时间是在循环中花费的时间,在C++中约为60ms,在Javascript中约为110ms.因此,对于主要使用直接缓冲区访问进行循环和计算的操作,首选C++.