use std::sync; use std::thread; use std::time; // Квадратная матрица хранится в куче как последовательность всех её элементов, при этом на этапе компиляции всегда известен её размер struct Matrix { inner: Vec<[i16; N]>, } impl Matrix { fn new() -> Matrix { Matrix { inner: vec![[0; N]; N], } } // Псевдослучайная генерация данных для матрицы fn random(seed: i16) -> Matrix { let mut matrix = Matrix::new(); for i in 0..N { for j in 0..N { matrix.inner[i][j] = i as i16 + j as i16 - seed; } } matrix } } // Рекурсивное получение определителя по первой строке, также включает необязательные аргументы, необходимые для случая с параллельностью fn recursive(matrix: &[&[i16]], from: Option, to: Option) -> i16 { let size = matrix.len(); match size { 0 => unreachable!(), 1 => matrix[0][0], 2 => matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0], 3.. => (from.unwrap_or(0)..to.unwrap_or(size)) .map(|c| { ((-1i16).pow(c as u32)) * matrix[0][c] * recursive( &matrix .iter() .skip(1) .map(|row| { row.iter() .zip(0..) .filter(|(_, i)| *i != c) .map(|(n, _)| *n) .collect::>() }) .collect::>>() .iter() .map(|r| r.as_slice()) .collect::>(), None, None, ) }) .sum(), } } fn parallel(matrix: &Matrix) -> i16 { let (result_sender, result_receiver) = sync::mpsc::channel::(); let matrix: &[&[i16]] = &matrix .inner .iter() .map(|r| r.as_slice()) .collect::>(); thread::scope(move |scope| { let chunk_size = N / M; let remainder = N % M; let mut chunks = Vec::new(); let mut start_col = 0; for i in 0..M { let end_col = start_col + chunk_size + if i < remainder { 1 } else { 0 }; chunks.push((start_col, end_col)); start_col = end_col; } chunks.into_iter().for_each(|(start_col, end_col)| { let sender = result_sender.clone(); scope.spawn(move || sender.send(recursive(matrix, Some(start_col), Some(end_col))).unwrap()); }); }); result_receiver.into_iter().sum() } // Замер времени выполнения, при этом размеры матриц и количество потоков известны на этапе компиляции fn benchmark() { let matrix = Matrix::::random(0); let start_time = time::Instant::now(); parallel::(&matrix); println!("Определитель для матрицы {0:>4}x{0:<4}: {1} сек ({2} потоков)", N, (time::Instant::now() - start_time).as_secs_f64(), M) } fn main() { benchmark::<8, 1>(); benchmark::<8, 2>(); benchmark::<8, 4>(); benchmark::<8, 8>(); benchmark::<10, 1>(); benchmark::<10, 2>(); benchmark::<10, 4>(); benchmark::<10, 8>(); benchmark::<11, 1>(); benchmark::<11, 2>(); benchmark::<11, 4>(); benchmark::<11, 8>(); benchmark::<12, 1>(); benchmark::<12, 2>(); benchmark::<12, 4>(); benchmark::<12, 8>(); }