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

时间:2015-02-13 20:39:33

标签: javascript c++ node.js performance

我一直在尝试使用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中设置值?

1 个答案:

答案 0 :(得分:10)

使用C ++

最大化类型化数组性能

我并不感到惊讶,这写得很慢,但你可以做很多事情来加快速度。关键的见解是,当在节点中处理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 ++。