Здравствуйте. Я тут немного решил поэксперементировать с параллельностью в расте и сделал маленький генератор фракталов. И был немного удивлен, когда увидел, то при распараллеливаниии на несколько тредов, производительность не только лишь не увеличивается, но еще и уменьшается! Это я криворукий или треды в расте нифига не параллельны?
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)
}
}
}