Nodejs method instances using multithreaded programming _node.js

Source: Internet
Author: User

In the previous blog not to say impossible, nodejs in the sleep, I introduced to you the use of Nodejs addon. Today's theme is still addon, continue to tap C + + 's ability to make up for nodejs weaknesses.

I have mentioned several times about the performance of Nodejs. In fact, in terms of language itself, Nodejs performance is still very high, although less than most static language, but the gap is not large; compared to other dynamic languages, the speed advantage is very obvious. But why do we often say that Nodejs is not capable of CPU-intensive scenarios? Because of its single-threaded nature, it does not take full advantage of CPUs for CPU-intensive scenarios. There is a famous law of Amdahl in computer science:

Suppose the total amount of work w can be decomposed into two parts: only the WS that can be serially computed and the WP that allows parallel computing. Then, in the case of P CPU parallel computation, performance can bring speedup times of Ascension. The Amdahl law describes what can and cannot be done in parallel. It is an ideal situation and the reality is much more complicated. For example, concurrency is likely to cause contention for resources, the need to increase a variety of locks, so that the parallel is often in the waiting state, concurrency will also bring additional operating system to the thread scheduling switching time overhead, add WS. However, in a task where WP is much larger than WS, and when multiple CPU cores are available, the parallel performance boost is considerable.

Okay, back to the Nodejs. We envision a calculated scenario: Calculate the number of prime numbers in 4000000. When this scenario is programmed to implement, the division is the main operation, does not involve memory, objects and other operations, theoretically able to ensure that Nodejs to run relatively fast speed, will not lag behind C too much, easy to compare.

JavaScript's search for prime numbers is already available in this blog, copied directly:

Copy Code code as follows:

function Zhishu_js (num) {
if (num = 1) {
return false;
}
if (num = 2) {
return true;
}
for (var i = 2; I <= math.sqrt (num); i++) {
if (num% i = = 0) {
return false;
}
}
return true;
}

Write another C-language version of:

Copy Code code as follows:

#include <math.h>

BOOL Zhishu (int num) {
if (num = 1) {
return false;
}
if (num = 2) {
return true;
}
for (int i = 2; I <= sqrt (num); i++) {
if (num% i = = 0) {
return false;
}
}
return true;
};

In Nodejs, we use a loop from 1 to 4000000 to retrieve prime numbers; In the C language, we set up several threads, define count 4000000, and each thread does the following: If Count is greater than 0, remove the value of count and calculate whether it is a prime number, Reduce count by 1 at the same time. Based on this idea, the JavaScript version is easy to write:

Copy Code code as follows:

var count = 0;

for (j = 1; j < 4000000; J + +) {
if (Zhishu (j)) {
count++;
}
}


The key difficulty is multithreaded programming in C language. Early-C + + does not consider the need for parallel computing, so there is no multithreaded support in the standard library. and different operating systems are usually implemented differently. To avoid this kind of trouble, we use pthread to handle threads.

Download the latest version of Pthread. Because I am not familiar with the Gyp, link rely on Lib for a half-day did not fix, and finally my way is, directly to the Pthread source code into the project directory, And in the Binding.gyp to add PTHREAD.C to the source code list, compile the project when the Pthread also compile once. The modified Binding.gyp is like this:

Copy Code code as follows:

{
"Targets": [
{
"Target_name": "Hello",
"Sources": ["hello.cc", "PTHREADS/PTHREAD.C"],
"Include_dirs": [
"<! (NODE-E \ "require (' Nan ')") ",
"Pthreads"
],
"Libraries": ["Ws2_32.lib"]
}
]
}

Of course, I have trouble with this method, if you only add Pthread lib and include directory references, and do not have dependency problems, it is the best, there is no need to use my method to do.

So then you're going to go into all of C + + threads and define a threading function:

Copy Code code as follows:

pthread_mutex_t lock;

void *thread_p (void *null) {
int num, x=0;
do{
Pthread_mutex_lock (&lock);
num=count--;
Pthread_mutex_unlock (&lock);
if (num>0) {
if (Zhishu (num)) x + +;
}else{
Break
}
}while (TRUE);
std::cout<< ' <<x<< ';
Pthread_exit (NULL);
return null;
}

Between threads and thread, the variable for count is competing against each other, and we need to make sure that only one thread can manipulate the count variable at the same time. We're through pthread_mutex_t lock; Add a mutual exclusion lock. When executing pthread_mutex_lock (&lock); , the thread checks the lock lock and, if locked, waits, repeats the check, blocks subsequent code runs, and locks up and executes subsequent code if the lock is released. Accordingly, Pthread_mutex_unlock (&lock); is to unlock the state.

Because compilers compile at the same time, compile optimization, if a statement does not explicitly do anything, the execution of other statements have no effect, the compiler will be optimized. In the code above, I've added code that counts the number of prime numbers, and if not, code like this:

Copy Code code as follows:

for (int j = 0; J < 4000000; J + +) {
Zhishu (j);
}

is skipped directly by the compiler and will not actually run.

Adding addon has been introduced, we implement from JavaScript to receive a parameter, representing the number of threads, and then create a specified number of threads in C to complete the search for prime numbers. Complete code:

Copy Code code as follows:

#include <nan.h>
#include <math.h>
#include <iostream>
#include "Pthreads\pthread.h"
#define MAX_THREAD 100
using namespace V8;

int count=4000000;
pthread_t Tid[max_thread];
pthread_mutex_t lock;

void *thread_p (void *null) {
    int num, x=0
    do{
   & nbsp;    Pthread_mutex_lock (&lock);
        num=count--;
        Pthread_mutex_unlock (&lock);
        if (num>0) {
             if (Zhishu (num)) x + +;
       }else{
             break;
       }
   }while (true);
    std::cout<< ' <<x<< ';
    pthread_exit (NULL);
    return null;
}

Nan_method (Zhishu) {
Nanscope ();
Pthread_mutex_init (&lock,null);
Double Arg0=args[0]->numbervalue ();
int c=0;
for (int j = 0; J < arg0 && j<max_thread; J + +) {
Pthread_create (&tid[j],null,thread_p,null);
}
for (int j = 0; J < arg0 && j<max_thread; J + +) {
Pthread_join (Tid[j],null);
}
Nanreturnundefined ();
}

void Init (handle<object> exports) {
Exports->set (NaNSymbol ("Zhishu"), Functiontemplate::new (Zhishu)->getfunction ());
}

Node_module (Hello, Init);

Phread_create can create threads, default is joinable, this time the child thread is subject to the main threads, phread_join block the main thread, wait for the child thread join until the child thread exits. If the child thread has exited, Phread_join will not do anything. Therefore, all threads are executed thread_join to ensure that all threads exit before the example main thread continues.

Refine the Nodejs script:

Copy Code code as follows:

var zhishu_c=require ('./build/release/hello.node '). Zhishu;
function Zhishu (num) {
if (num = 1) {
return false;
}
if (num = 2) {
return true;
}
for (var i = 2; I <= math.sqrt (num); i++) {
if (num% i = = 0) {
return false;
}
}
return true;
}

Console.time ("C");
Zhishu_c (100);
Console.timeend ("C");

Console.time ("JS");
var count=0;
for (j = 1; j < 4000000; J + +) {
if (Zhishu (j)) {
count++;
}
}
Console.log (count);
Console.timeend ("JS");

Look at the test results:

In a single thread, although the speed of C + + is 181% of Nodejs, we think that in the dynamic language, the performance is very good. Two-thread speed increases most obviously because my computer is a dual-core four-thread CPU, which may already be being processed using two cores. The maximum speed of a 4 thread is at this point, and it should be the limit that a dual-core four thread can reach, and it cannot be lifted when the thread increases. Of the above Amdahl Law, p has reached the upper limit of 4. Adding more threads increases the timing of the operating system process and increases the time of the lock, although it also increases the competition for CPU time, but overall, the WS increases significantly and performance is degraded. If you do this experiment on an idle machine, the data should be better.

From this experiment, we can conclude that for CPU-intensive operations, to the static language to do, more efficient, if more involved in the calculation of memory, string, array, recursion and other operations (later verification), performance improvement is even more amazing. At the same time, reasonable use of multithreading can effectively improve processing efficiency, but not the more the more the better, according to the situation of the machine reasonable configuration.

For Nodejs itself, is really not good at dealing with CPU-intensive tasks, but with the experience of this article, I think, to overcome this obstacle, is not an impossible thing.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.