polevoy_sergey_lab_6 #218
11
polevoy_sergey_lab_6/cargo.toml
Normal file
11
polevoy_sergey_lab_6/cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "matrix"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
opt-level = 3
|
||||
panic = "abort"
|
||||
|
||||
[dependencies]
|
BIN
polevoy_sergey_lab_6/image.png
Normal file
BIN
polevoy_sergey_lab_6/image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
13
polevoy_sergey_lab_6/readme.md
Normal file
13
polevoy_sergey_lab_6/readme.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Лабораторная работа №6
|
||||
## Полевой Сергей ПИбд-42
|
||||
### Реализация
|
||||
|
||||
Было решено распределять работу по потокам в виде диапазонов столбцов матрицы, по которым каждый поток по отдельности найдёт определитель минора, далее результаты работ каждого потока передаются по mpsc каналу и суммируется для окончательного результата.
|
||||
|
||||
#### Скриншот результата работы
|
||||
![alt text](image.png)
|
||||
|
||||
#### Выводы
|
||||
Подобно результату прошлой лабораторной работы, очевидного выигрыша программа достигает при должно большом размере матрицы, так как при малых значениях размера больше времени тратится на создание и управление потоками.
|
||||
|
||||
#### Демонстрация работы доступна по [ссылке](https://disk.yandex.ru/i/lv-Szz2Xzpvx7w)
|
125
polevoy_sergey_lab_6/src/main.rs
Normal file
125
polevoy_sergey_lab_6/src/main.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use std::sync;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
|
||||
// Квадратная матрица хранится в куче как последовательность всех её элементов, при этом на этапе компиляции всегда известен её размер
|
||||
struct Matrix<const N: usize> {
|
||||
inner: Vec<[i16; N]>,
|
||||
}
|
||||
|
||||
impl<const N: usize> Matrix<N> {
|
||||
fn new() -> Matrix<N> {
|
||||
Matrix {
|
||||
inner: vec![[0; N]; N],
|
||||
}
|
||||
}
|
||||
|
||||
// Псевдослучайная генерация данных для матрицы
|
||||
fn random(seed: i16) -> Matrix<N> {
|
||||
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<usize>, to: Option<usize>) -> 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::<Vec<i16>>()
|
||||
})
|
||||
.collect::<Vec<Vec<i16>>>()
|
||||
.iter()
|
||||
.map(|r| r.as_slice())
|
||||
.collect::<Vec<&[i16]>>(),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
})
|
||||
.sum(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parallel<const N: usize, const M: usize>(matrix: &Matrix<N>) -> i16 {
|
||||
let (result_sender, result_receiver) = sync::mpsc::channel::<i16>();
|
||||
let matrix: &[&[i16]] = &matrix
|
||||
.inner
|
||||
.iter()
|
||||
.map(|r| r.as_slice())
|
||||
.collect::<Vec<&[i16]>>();
|
||||
|
||||
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<const N: usize, const M: usize>() {
|
||||
let matrix = Matrix::<N>::random(0);
|
||||
|
||||
let start_time = time::Instant::now();
|
||||
parallel::<N, M>(&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>();
|
||||
}
|
Loading…
Reference in New Issue
Block a user