카테고리 없음

러스트 멀티 스레드 구현 예제

23년에 찾아온 특이점 중 하나는 러스트 언어를 시작했다는 것이다

파이썬을 하면서 항상 GIL이 존재해서(물론 병렬 처리를 도와주는 라이브러리들이 많지만)

멀티스레드를 직접 사용하지 못했는데, 러스트 언어를 사용해 네이티브하게 멀티스레드를 사용해볼 수 있었다.

 

정말 안타깝게도 티스토리에서는 코드블럭에 러스트 언어에 대한 구현이 없어 하이라이트가 제대로 들어가지 않는

단점은 덤으로 알게 되었다.

// 필요한 라이브러리와 모듈을 가져옵니다.
use std::thread;
use std::time::Instant;

fn main() {
    // 데이터를 초기화합니다.
    let data1 = vec![999; 1000000000];
    let data2 = vec![999; 250000000];
    let data3 = vec![999; 250000000];
    let data4 = vec![999; 250000000];
    let data5 = vec![999; 250000000];

    // 단일 스레드에서 작업을 수행하고 시간을 측정합니다.
    let thread_start = Instant::now();
    let result1: Vec<i32> = data1
    .into_iter()
    .map(|i| i + 2)
    .collect();
    let thread_duration = thread_start.elapsed().as_secs_f32();
    eprintln!("thread_duration = {:?}", thread_duration);
    eprintln!("result1. = {:?}", result1.len());

    // 멀티스레드에서 작업을 수행하고 시간을 측정합니다.
    let multi_thread_start = Instant::now();
    let handle1 = thread::spawn(| | {
        let result: Vec<i32> = data2
        .into_iter()
        .map(|i| i + 2)
        .collect();
        return result
    });

    let handle2 = thread::spawn(|| {
        let result: Vec<i32> = data3
        .into_iter()
        .map(|i| i + 2)
        .collect();
        return result
    });

    let  handle3 = thread::spawn(|| {
        let result: Vec<i32> = data4
        .into_iter()
        .map(|i| i + 2)
        .collect();
        return result
    });

    let handle4 = thread::spawn(|| {
        let result: Vec<i32> = data5
        .into_iter()
        .map(|i| i + 2)
        .collect();
        return result
    });

    // 각 스레드의 결과를 수집합니다.
    let result2 = handle1.join().unwrap();
    let result3 = handle2.join().unwrap();
    let result4 = handle3.join().unwrap();
    let result5 = handle4.join().unwrap();

    // 멀티스레드 작업의 총 시간을 출력합니다.
    let multi_thread_duration = multi_thread_start.elapsed().as_secs_f32();
    eprintln!("multi_thread_duration = {:?}", multi_thread_duration);
    
    // 각 결과의 길이만 출력합니다 (값 사용으로 컴파일러 최적화 방지)
    eprintln!("result1 = {:?}", result1.len());
    eprintln!("result2 = {:?}", result2.to_owned().len());
    eprintln!("result3 = {:?}", result3.to_owned().len());
    eprintln!("result4 = {:?}", result4.to_owned().len());
    eprintln!("result5 = {:?}", result5.to_owned().len());

}

 

 

thread의 결과는 0.678초

multi-thread의 결과는 0.263초의 결과가 나온다.

물론 시간 측정에서 데이터를 분할하는 과정에 대해서 시간을 측정하지 않아, 조금 더 효율적으로 멀티스레드가 동작하게 된 것도 있으며,

데이터의 크기가 클수록 차이가 크게 나는 경향이 있다.

 

추가 실험으로 Vec<i32>로 된 것을 Vec<i8>로 변경 후 작업에 임했더니

싱글스레드 7.3초

멀티스레드 5.0초의 결과값이 나오는 것을 확인했다

 

이는 늘어난 코드에 대비해서 그다지 효율적이지 못한 상황으로 보인다.

반응형