프로그래밍 지식/C++

C++문법 / 멀티 스레딩, Multi-threading 연산

게임이 더 좋아 2021. 12. 2. 23:08
반응형
728x170

 

우리가 스레드를 만드는 이유는..

효율적으로 사용하기 위해서다.

 

1부터 10000까지 더하는 작업은 얼마나 걸릴까???

물론 우리는 n(n+1)/2라는 것을 알고 있지만

컴퓨터는 한 번 경험을 통해서 알게 해주고 싶다.

해보자

 

우선 스레드 하나로 돌려보자

#include <iostream>
#include <thread>
#include<chrono>

using namespace std;
using namespace chrono;



void func1(int *result) {
    for (int i = 1; i <= 10000; i++) {
        *result += i;
    }
}



int main() {

    int sum = 0;
    steady_clock::time_point start = steady_clock::now();
    thread t1(func1, &sum); //스레드 객체 t1을 생성 후 해당 스레드로 func1 실행
    t1.join();
    steady_clock::time_point end = steady_clock::now();
    cout << sum << '\n';

    duration<double> sec = end - start;
    cout << "elapsed time " << sec.count();

}

 

결과는?

 

대략 0.03초 정도 걸렸다.

 


 

그럼 화끈하게 10개 이용해볼까??

근데 스레드에게 인자를 전달해줘서 갱신되게 해보자.

thread를 생성할 때 같이 전달해준다.

#include <iostream>
#include <thread>
#include <chrono>
#include <vector>

using namespace std;
using namespace chrono;



void func(int start, int end, int *result) {
    int s = 0;
    for (int i = start; i <= end; i++) {
        s += i;
    }
    *result += s;
}



int main() {

    int sum = 0;
    vector<thread> threads;


    steady_clock::time_point start = steady_clock::now();
    for (int i = 0; i < 10; i++) {
        threads.push_back(thread(func, i * 1000 + 1, i * 1000 + 1000, &sum)); // 스레드 10개를, 범위를 나누어주어서 실행
    }

    for (int i = 0; i < 10; i++) {
        threads[i].join(); //스레드 10개 반환 기다림
    }
    steady_clock::time_point end = steady_clock::now();


    cout << sum << '\n';

    duration<double> sec = end - start;
    cout << "elapsed time " << sec.count();

}

 

 

결과는???

 

???????

뭐야 더 걸려..?

 

3가지 경우가 있겠다.

 

1. 내 잘못

2. 스레드 생성자체가 오버헤드가 더 심함 -> 일 것 같다. 1부터 1만하는 것은 너무 작은 연산이잖아..

3. OS 스케줄러 탓

 

???

다른 분의 도움을 받아 

다르게 작성해보았다.

 

#include <iostream>
#include <thread>
#include <chrono>
#include <vector>

using namespace std;
using namespace chrono;



void worker(vector<int>::iterator start, vector<int>::iterator end,int* result) {
    int sum = 0;
    for (auto itr = start; itr < end; ++itr) {
        sum += *itr;
    }
    *result = sum;

}


int main() {

    //10000짜리 컨테이너에 순서대로 값 초기화
    vector<int> data(10000);
    for (int i = 0; i < 10000; i++) {
        data[i] = i+1;
    }


    // 각 쓰레드에서 계산된 부분 합들을 저장하는 벡터
    vector<int> partial_sums(10);

    //thread 넣을 벡터
    vector<thread> workers;

    steady_clock::time_point start = steady_clock::now();
    for (int i = 0; i < 10; i++) {
        workers.push_back(thread(worker,
                                data.begin() + i * 1000,
                                data.begin() + (i + 1) * 1000,
                                &partial_sums[i]));
    }

    for (int i = 0; i < 10; i++) {
        workers[i].join();
    }

    int total = 0;
    for (int i = 0; i < 10; i++) {
        total += partial_sums[i];
    }
    steady_clock::time_point end = steady_clock::now();

    cout << total << '\n';
    duration<double> sec = end - start;
    cout << "elapsed time " << sec.count();

}

 

결과는???

 

???

 

내가 잘못한 것이 아니구나..ㅎ

사실 이 글을 읽는 사람을 깨우쳐주려고 했다.

 

어떠한 작업이냐에 따라 멀티스레딩이 유용할 수도 있고

그렇지 않을수도 있다.

싱글코어면 context switching 오버헤드가 더 크기 때문에 더 오래 걸릴 것이고

thread 생성하는 것도 오버헤드가 커서 적당히 나누는 것이 필요하고

간단한 작업은 그냥하는 것이 필요하다.

 

아무튼 멀티 스레딩을 이용해서 연산을 해보았다.

 

728x90
반응형
그리드형