diff --git a/polevoy_sergey_lab_6/cargo.toml b/polevoy_sergey_lab_6/cargo.toml new file mode 100644 index 0000000..42b884c --- /dev/null +++ b/polevoy_sergey_lab_6/cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "matrix" +version = "0.1.0" +edition = "2021" + +[profile.release] +strip = true +opt-level = 3 +panic = "abort" + +[dependencies] diff --git a/polevoy_sergey_lab_6/image.png b/polevoy_sergey_lab_6/image.png new file mode 100644 index 0000000..985cb49 Binary files /dev/null and b/polevoy_sergey_lab_6/image.png differ diff --git a/polevoy_sergey_lab_6/readme.md b/polevoy_sergey_lab_6/readme.md new file mode 100644 index 0000000..95cb11e --- /dev/null +++ b/polevoy_sergey_lab_6/readme.md @@ -0,0 +1,13 @@ +# Лабораторная работа №6 +## Полевой Сергей ПИбд-42 +### Реализация + +Было решено распределять работу по потокам в виде диапазонов столбцов матрицы, по которым каждый поток по отдельности найдёт определитель минора, далее результаты работ каждого потока передаются по mpsc каналу и суммируется для окончательного результата. + +#### Скриншот результата работы +![alt text](image.png) + +#### Выводы +Подобно результату прошлой лабораторной работы, очевидного выигрыша программа достигает при должно большом размере матрицы, так как при малых значениях размера больше времени тратится на создание и управление потоками. + +#### Демонстрация работы доступна по [ссылке](https://disk.yandex.ru/i/lv-Szz2Xzpvx7w) \ No newline at end of file diff --git a/polevoy_sergey_lab_6/src/main.rs b/polevoy_sergey_lab_6/src/main.rs new file mode 100644 index 0000000..a97b5ee --- /dev/null +++ b/polevoy_sergey_lab_6/src/main.rs @@ -0,0 +1,125 @@ +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>(); +}