LINUX.ORG.RU

параллельность в расте

 ,


1

9

Здравствуйте. Я тут немного решил поэксперементировать с параллельностью в расте и сделал маленький генератор фракталов. И был немного удивлен, когда увидел, то при распараллеливаниии на несколько тредов, производительность не только лишь не увеличивается, но еще и уменьшается! Это я криворукий или треды в расте нифига не параллельны?

extern crate image;

use std::thread;
use std::sync::{Mutex, Arc};
use std::time;
use image::*;
use std::env;

fn calculate_point(x : f64, y : f64, depth : usize) -> f32 {
    let mut zx = 0.0;
    let mut zy = 0.0;
    let mut zx1;
    let mut zy1;
    for i in 0 .. depth {
        zx1 = (zx * zx) - (zy * zy) + x;
        zy1 = zx * zy * 2.0 + y;
        if zx1 * zx1 + zy1 * zy1 > 4.0 {
            return (i as f32) / (depth as f32);
        }
        else {
            zx = zx1;
            zy = zy1;
        }
    }
    return 1.0;//depth as f32;
}

fn get_color(colors : &Vec<[f32;3]>, buffer : &mut Vec<[f32;3]>, x : f32) -> Rgb<u8> {
    let mut len = colors.len() - 1;
    for i in 0 .. len {
        for j in 0 .. 3 {
            buffer[i][j] = colors[i][j] + (colors[i+1][j] - colors[i][j]) * x
        }
    }
    while len > 1 {
        for i in 0 .. len - 1 {
            for j in 0 .. 3 {
                buffer[i][j] = buffer[i][j] + (buffer[i+1][j] - buffer[i][j]) * x
            }
        }
        len -= 1;
    }
    return Rgb([buffer[0][0] as u8, buffer[0][1] as u8, buffer[0][2] as u8]);
}

fn make_pic_1th(width : u32, height : u32) -> RgbImage {
    let mut pic = ImageBuffer::new(width, height);
    let colors : Vec<[f32;3]> = vec![[0.0,0.0,0.0], [255.0,0.0,0.0], [255.0,255.0,0.0], [255.0,255.0,255.0]];
    let mut buffer = colors.clone();
    for i in 0 .. width {
        let x = (i as f64) / (width as f64) * 2.0 - 1.0;
        for j in 0 .. height {
            let y = (j as f64) / (height as f64) * 2.0 - 1.0;
            (*pic.get_pixel_mut(i,j)) = get_color(&colors, &mut buffer, calculate_point(x, y, 1000));
        }
    }
    pic
}

unsafe fn calc_rows(index : u32, step : u32, width : u32, height : u32, pic : SendPtr<RgbImage>, live_flag : Arc<Mutex<bool>>) {
    let colors : Vec<[f32;3]> = vec![[0.0,0.0,0.0], [255.0,0.0,0.0], [255.0,255.0,0.0], [255.0,255.0,255.0]];
    let mut buffer = colors.clone();
    let pic       : *mut RgbImage = match pic {SendPtr(a) => a};
    for i in 0 .. width {
        let x = (i as f64) / (width as f64) * 2.0 - 1.0;
        let mut j = index;
        while j < height {
            let y = (j as f64) / (height as f64) * 2.0 - 1.0;
            (*(*pic).get_pixel_mut(i,j)) = get_color(&colors, &mut buffer, calculate_point(x, y, 1000));
            j += step;
        }
    }
    (*live_flag.lock().unwrap()) = false;
}

struct SendPtr<A>(*mut A);
unsafe impl<A> Send for SendPtr<A> {}
unsafe impl<A> Sync for SendPtr<A> {}

fn make_pic_3th(width : u32, height : u32) -> RgbImage {
    let mut pic = ImageBuffer::new(width, height);
    let f1 = Arc::new(Mutex::new(true));
    let f2 = Arc::new(Mutex::new(true));
    let f3 = Arc::new(Mutex::new(true));
    unsafe {
        macro_rules! spawn {($i:expr,$m:expr,$flag:expr) => {
            let ppic  = SendPtr(&mut pic);
            let pflag = $flag.clone();
            thread::spawn(move|| {calc_rows($i, $m, width, height, ppic, pflag)});
        }};
        spawn!(0, 3, f1);
        spawn!(1, 3, f2);
        spawn!(2, 3, f3);
    }
    let dur = time::Duration::from_millis(50);
    loop {
        let a : bool = *f1.lock().unwrap();
        let b : bool = *f2.lock().unwrap();
        let c : bool = *f2.lock().unwrap();
        if a || b || c {
            thread::sleep(dur)
        } else {
            break
        }
    }
    pic
}

fn main() {
    let args : Vec<String> = env::args().collect();
    let pic = if args[1] == "1" {make_pic_1th(1000,1000)} else {make_pic_3th(1000, 1000)};
    match pic.save("out.png") {
        Ok(_) => (),
        Err(e) => {
            println!("error: {:?}", e)
        }
    }
}

★★★★★
Ответ на: комментарий от Aswed

Да, я сам уже тут поковыриваю этот код, вижу что не повлияло) Кстати, не знаю как ты мерил, но у меня при выполнении в 3 потока в 2 раза ускорение.

mersinvald ★★★★★
()
Ответ на: комментарий от mersinvald

Возможно, что у меня тут на работе мак не хочет параллелить по-нормальному. Попробую дома на линуске запустить.

Aswed ★★★★★
() автор топика
Ответ на: комментарий от mersinvald

вот собсна мои результаты

⧖ 2:46:17 λ> time ../target/release/julia 3                                                                                                                                           ~/code/tests.rust/julia/src
../target/release/julia 3  2.02s user 0.01s system 266% cpu 0.762 total
⧖ 2:46:23 λ> time ../target/release/julia 1                                                                                                                                           ~/code/tests.rust/julia/src
../target/release/julia 1  1.86s user 0.01s system 99% cpu 1.881 total

Aswed ★★★★★
() автор топика
Ответ на: комментарий от Aswed

По моему у вас все нормально работает.
Не рассматриваем unsafe и тд.

[someuser@somehost julia]$ time target/release/julia 1

real    0m1.769s
user    0m1.767s
sys     0m0.000s
[someuser@somehost julia]$ time target/release/julia 3

real    0m0.470s
user    0m1.217s
sys     0m0.007s

uglym8
()
Ответ на: комментарий от Aswed

Может ты попутал user time и total time? Я вот смотрю на твои результаты с мака и вижу что 1 тред отработал за 1.881 секунды а три треда справились за 0.762 секунды, что в 2.57 раз быстрее.

pftBest ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.