简体   繁体   English

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

[英]Node.JS performance vs native C++ addon when populating an Int32Array

I've been experimenting with Node.JS and C++ addons and found that populating an Int32Array is considerably slower when using the C++ addon rather than directly doing so in Node.JS / JavaScript. 我一直在尝试使用Node.JS和C ++插件,发现在使用C ++插件时填充Int32Array要慢得多,而不是在Node.JS / JavaScript中直接填充。

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

Does anyone know why this is? 有人知道为什么吗? My test code consists of a fairly large array and for loops containing if statements. 我的测试代码包含了相当大阵if语句循环。

I suspect I'm populating the array incorrectly in my C++ addon. 我怀疑我在C ++插件中错误地填充了数组。 (?) (?)

JavaScript: 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++ Addon: 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: Just to add, the functions I'm using in my C++ code are V8 functions and weren't defined by myself. 编辑:只是添加,我在我的C ++代码中使用的函数是V8函数,并不是我自己定义的。 Is there another way to set values in an Int32Array without using these? 有没有其他方法在Int32Array中设置值而不使用它们?

Maxing out Typed Array Performance using C++ 使用C ++最大化Typed Array性能

I'm not surprised this is slow as written, but there is a lot you can do to speed it up. 我并不感到惊讶,这写得很慢,但你可以做很多事情来加速它。 The critical insight is that when dealing with JavaScript typed arrays in node, you can gain access to the memory buffer and operate on that directly. 关键的见解是,当在节点中处理JavaScript类型的数组时,您可以访问内存缓冲区并直接对其进行操作。

The main source of slowness 缓慢的主要来源

Though when dealing with normal JavaScript arrays/objects, the following are necessary 虽然在处理普通的JavaScript数组/对象时,以下是必要的

Integer::New( isolate , value ) 整数::新( 隔离

and

testArray->Set( value ) testArray-> Set( value

So for example the following line 例如,以下行

testArray->Set(i, Integer::New(isolate, 0));

creates a new Number object, converts the integer 0 to a double since all JavaScript numbers are double, calls Set with the Number object, then converts the double back to an integer because it's storing the value in a Int32 typed array, and then destructs the Number object. 创建一个新的Number对象,将整数0转换为double,因为所有JavaScript数都是double,使用Number对象调用Set ,然后将double转换回整数,因为它将值存储在Int32类型的数组中,然后析构数字对象。 This happens 3 million times. 这发生了300万次。

An improvement 一种提升

But typed arrays are different, and the call GetIndexedPropertiesExternalArrayData gives one access to the underlying buffer, which for a Int32Array is a buffer of int . 但是类型化数组是不同的,并且调用GetIndexedPropertiesExternalArrayData提供对底层缓冲区的一个访问,对于Int32Array ,它是int的缓冲区。 This allows the C++ function to be re-written to avoid all of those allocations and casts: 这允许重写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);
}

Some measurements 一些测量

Replacing with the above makes things faster, but how much faster needs a test. 用上面的代替可以让事情变得更快,但是测试需要多快。 The following package can be cloned and when run (using node 0.12.5) results in the following 可以克隆以下包,并在运行时(使用节点0.12.5)导致以下结果

  Performance Tests
    ✓ via javascript (169ms)
    ✓ via c++ (141ms)

So that alone makes using C++ faster, but maybe not all that amazing, but if both the Javascript and the C++ loops (see the src) are commented out, and when only the array allocation is included: 因此,单独使用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 
/*
...

Then the time changes to 然后时间变为

  Performance Tests
    ✓ via javascript (62ms)
    ✓ via c++ (80ms)

In other words, simply allocating the array takes approximately 60ms in JavaScript, and 80ms in the C++ module. 换句话说,简单地分配数组在JavaScript中大约需要60ms,在C ++模块中需要80ms。 But that means that the rest of the time is the time spent in the loop, which is approximately 60ms in C++ and 110ms in Javascript. 但这意味着剩下的时间是在循环中花费的时间,在C ++中约为60ms,在Javascript中约为110ms。 And so for actions that are predominately loops and calculations using direct buffer access, C++ is preferred. 因此,对于主要使用直接缓冲区访问进行循环和计算的操作,首选C ++。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM