nodejs_node.js에서 멀티스레드 프로그래밍을 사용하는 방법의 예

WBOY
풀어 주다: 2016-05-16 16:08:02
원래의
2282명이 탐색했습니다.

이전 블로그 포스팅 불가능하다고 하지 말고 sleep을 nodejs로 구현하세요에서 nodejs 애드온 사용법을 소개한 적이 있습니다. 오늘의 주제는 여전히 애드온입니다. 계속해서 c/c의 기능을 탐색하고 nodejs의 약점을 보완하세요.

저는 nodejs의 성능 문제에 대해 여러 번 언급했습니다. 실제로 언어 자체에 관한 한 nodejs의 성능은 여전히 ​​매우 높습니다. 비록 대부분의 정적 언어만큼 좋지는 않지만 다른 동적 언어에 비해 격차는 크지 않습니다. . 그런데 nodejs가 CPU 집약적인 시나리오를 수행할 수 없다고 자주 말하는 이유는 무엇입니까? 단일 스레드 특성으로 인해 CPU 집약적인 시나리오에서는 CPU를 완전히 활용할 수 없습니다. 컴퓨터 과학에는 유명한 암달의 법칙이 있습니다:

총 작업 부하 W를 두 부분, 즉 직렬 계산만 가능한 Ws와 병렬 계산이 가능한 Wp로 분해할 수 있다고 가정합니다. 그러면 p개 CPU의 병렬 컴퓨팅의 경우 속도 향상 시간을 통해 성능을 향상시킬 수 있습니다. 암달의 법칙은 병렬 처리가 할 수 있는 것과 할 수 없는 것을 설명합니다. 이는 이상적인 상황이지만 실제 상황은 훨씬 더 복잡할 것입니다. 예를 들어, 동시성은 리소스에 대한 경합을 야기하여 다양한 잠금을 추가해야 하며, 이로 인해 종종 병렬성이 대기 상태로 남게 됩니다. 또한 동시성은 운영 체제가 스레드 스케줄링을 전환하는 데 추가 시간 오버헤드를 발생시켜 Ws를 증가시킵니다. 그러나 작업에서 Wp가 Ws보다 훨씬 크고 여러 CPU 코어를 사용할 수 있는 경우 병렬 처리로 인한 성능 향상은 상당합니다.

자, nodejs로 돌아갑니다. 계산 시나리오를 상상해 봅시다: 4,000,000 내의 소수의 수를 계산하십시오. 이 시나리오를 프로그래밍하면 나누기 작업이 주로 사용되며 메모리 및 객체와 같은 작업은 포함되지 않습니다. 이론적으로 nodejs가 상대적으로 빠른 속도로 실행되고 c보다 크게 뒤처지지 않도록 보장할 수 있어 편리합니다. 비교.

JavaScript에서 소수를 찾는 방법은 이 블로그에서 제공됩니다. 직접 복사하세요.

코드 복사 코드는 다음과 같습니다.

함수 zishu_js(num) {
If (num == 1) {
         false를 반환합니다.
}
If (숫자 == 2) {
        true를 반환합니다.
}
for (var i = 2; i <= Math.sqrt(num); i ) {
If (num % i == 0) {
              false를 반환합니다.
}
}
true를 반환합니다.
}

다른 C 언어 버전 작성:

코드 복사 코드는 다음과 같습니다.

#include

bool zishu(int num){
If (num == 1) {
         false를 반환합니다.
}
If (숫자 == 2) {
        true를 반환합니다.
}
for (int i = 2; i <= sqrt(num); i ) {
If (num % i == 0) {
              false를 반환합니다.
}
}
true를 반환합니다.
};

nodejs에서는 1부터 4000000까지의 루프를 사용하여 소수를 검색합니다. C 언어에서는 여러 스레드를 설정하고 개수를 4000000으로 정의합니다. 각 스레드는 다음을 수행합니다. 개수가 0보다 크면 제거합니다. count의 값이며, 소수인지 여부를 계산하고 count를 1씩 감소시킵니다. 이 아이디어에 따르면 자바스크립트 버전은 작성하기 쉽습니다.

코드 복사 코드는 다음과 같습니다.

변수 개수 = 0;

for (j = 1; j < 4000000; j ) {
If(zhishu(j)){
백작 ;
}
}


가장 어려운 점은 C 언어의 다중 스레드 프로그래밍입니다. c/c 초기에는 병렬 컴퓨팅의 필요성을 고려하지 않았기 때문에 표준 라이브러리에서는 멀티스레딩 지원이 제공되지 않았습니다. 운영 체제마다 일반적으로 구현이 다릅니다. 이 문제를 피하기 위해 우리는 pthread를 사용하여 스레드를 처리합니다.

pthread 최신 버전을 다운로드하세요. gyp에 익숙하지 않아서 링크 의존성 lib를 수정하는데 시간이 많이 걸렸고, 결국 제 방법은 pthread의 소스코드를 프로젝트 디렉토리에 직접 넣고, 소스코드에 pthread.c를 추가하는 방법이었습니다. 바인딩.gyp에 목록을 작성하고, 프로젝트 컴파일 시 pthread를 한 번 컴파일합니다. 수정된 바인딩.gyp은 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.

{
"대상": [
{
"target_name": "안녕하세요",
"소스": [ "hello.cc","pthreads/pthread.c" ],
"include_dirs": [
" "p스레드"
],
"라이브러리": ["Ws2_32.lib"]
}
]
}

물론 내 방법은 매우 번거롭습니다. lib에 대한 참조를 추가하고 pthread에 디렉터리를 포함하기만 하고 종속성 문제가 없다면 내 방법을 사용할 필요가 없습니다.

그럼 C/C 멀티스레딩에 대해 자세히 알아보고 스레드 처리 기능을 정의해 보겠습니다.

코드 복사 코드는 다음과 같습니다.

pthread_mutex_t 잠금;

void *thread_p(void *null){
정수 숫자, x=0;
하세요{
          pthread_mutex_lock(&잠금);
         숫자=개수--;
         pthread_mutex_unlock(&lock);
If(숫자>0){
If(zhishu(num))x ;
         }그 외{
             휴식;
}
}동안(true);
표준::cout<<' '< pthread_exit(NULL);
        null을 반환합니다.
}

스레드 간에는 count 변수가 서로 경쟁합니다. 동시에 하나의 스레드만 count 변수를 작동할 수 있도록 해야 합니다. pthread_mutex_t lock;을 통해 뮤텍스 잠금을 추가합니다. pthread_mutex_lock(&lock);이 실행되면 스레드는 잠금 상태를 확인하고 잠금이 해제되면 후속 코드 실행을 차단하고 후속 코드를 실행합니다. 이에 따라 pthread_mutex_unlock(&lock);은 잠금 상태를 잠금 해제하는 것입니다.

컴파일러는 컴파일하는 동안 컴파일 최적화를 수행하므로 문이 명확하게 아무것도 수행하지 않고 다른 문 실행에 영향을 주지 않으면 컴파일러에 의해 최적화됩니다. 위의 코드에는 소수의 개수를 세는 코드를 추가했습니다. 그렇지 않은 경우에는 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.

for (int j = 0; j < 4000000; j ) {
zishu(j);
}

은 컴파일러에 의해 직접 건너뛰어 실제로 실행되지 않습니다.

애드온을 추가하는 작성 방법이 도입되었습니다. 자바스크립트에서 스레드 수를 나타내는 매개변수를 받은 다음 c에서 지정된 수의 스레드를 생성하여 소수 검색을 완료합니다. 전체 코드:

코드 복사 코드는 다음과 같습니다.

#include
#include
#include
#include "pthreadspthread.h"
#MAX_THREAD 100 정의
네임스페이스 v8 사용;

정수=4000000;
pthread_t tid[MAX_THREAD];
pthread_mutex_t 잠금;

void *thread_p(void *null){
    정수 숫자, x=0;
    하세요{
        pthread_mutex_lock(&잠금);
        숫자=개수--;
        pthread_mutex_unlock(&잠금);
        if(숫자>0){
            if(zhishu(num))x ;
        }그밖에{
            휴식;
        }
    }동안(true);
    표준::cout     pthread_exit(NULL);
    null을 반환합니다.
}

NAN_METHOD(즈슈){
    NanScope();
    pthread_mutex_init(&lock,NULL);
    double arg0=args[0]->NumberValue();
    int c=0;
    for (int j = 0; j         pthread_create(&tid[j],NULL,thread_p,NULL);
    }
    for (int j = 0; j         pthread_join(tid[j],NULL);
    }
    NanReturnUndefine();
}

void Init(Handle 내보내기){
    내보내기->Set(NanSymbol("zhishu"), FunctionTemplate::New(Zhishu)->GetFunction());
}

NODE_MODULE(안녕하세요, Init);

 phread_create可以创建线程, 默认是joinable, 这个时候子线程受程;主线程;phread_join阻塞住主线程,等待子线程join,直到子线程退出。如果子线程已退流,则phread_join不会做任何事。所以对所有的线程city执行thread_join,可以保证所有的线程退流后才会例主线程继续进行。

完善一下nodejs脚本:

复代码 代码如下:

var zishu_c=require('./build/Release/hello.node').zhishu;
함수 zishu(num) {
    if (num == 1) {
        false를 반환합니다.
    }
    if (숫자 == 2) {
        true를 반환합니다.
    }
    for (var i = 2; i <= Math.sqrt(num); i ) {
        if (num % i == 0) {
            false를 반환합니다.
        }
    }
    true를 반환합니다.
}

console.time("c");
    zishu_c(100);
console.timeEnd("c");

console.time("js");
var 개수=0;
for (j = 1; j     if(zhishu(j)){
        카운트 ;
    }
}
console.log(개수);
console.timeEnd("js");

테스트 결과 살펴보기:

단일 스레드에서는 C/C의 실행 속도가 nodejs의 181%이지만 동적 언어에서는 이 결과가 여전히 매우 좋다고 생각합니다. 듀얼 스레드를 사용할 때 속도 향상이 가장 뚜렷하게 나타납니다. 이는 내 컴퓨터에 듀얼 코어 4스레드 CPU가 있고 현재 처리에 두 개의 코어가 사용되고 있을 가능성이 있기 때문입니다. 이때 속도는 스레드가 4개 있을 때 최대치에 이르며, 스레드 수를 늘려도 속도는 향상될 수 없습니다. 위의 암달의 법칙에서 p는 4의 상한에 도달했습니다. 더 많은 스레드를 추가하면 운영 체제 프로세스 스케줄링 시간과 잠금 시간이 늘어납니다. CPU 시간에 대한 경쟁도 증가하지만 전반적으로 Ws의 증가는 더욱 뚜렷해지고 성능은 저하됩니다. 유휴 컴퓨터에서 이 실험을 수행하면 데이터가 더 좋아질 것입니다.

이 실험을 통해 CPU 집약적인 작업의 경우 계산에 더 많은 메모리, 문자열, 배열, 재귀 등이 포함되면 효율성이 크게 향상된다는 결론을 내릴 수 있습니다. (추후 검증 예정) 성능 향상은 더욱 놀랍습니다. 동시에 멀티 스레드를 합리적으로 사용하면 처리 효율성이 효과적으로 향상될 수 있지만 스레드가 많다고 해서 항상 더 나은 것은 아닙니다. 기계의 조건에 따라 적절하게 구성해야 합니다.

Nodejs 자체는 실제로 CPU 집약적인 작업을 잘 처리하지 못하지만, 이 글의 경험으로 볼 때 이 장애물을 극복하는 것이 불가능하지는 않다고 생각합니다.

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿