forked from Alexey/DAS_2024_1
Merge pull request 'zhimolostnova_anna_lab_6' (#95) from zhimolostnova_anna_lab_6 into main
Reviewed-on: Alexey/DAS_2024_1#95
This commit is contained in:
commit
62290fc43d
87
zhimolostnova_anna_lab_6/README.md
Normal file
87
zhimolostnova_anna_lab_6/README.md
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
# Отчет по лабораторной работе №6
|
||||||
|
|
||||||
|
## Описание задачи
|
||||||
|
|
||||||
|
Данная работа нацелена на изучение эффективности параллельных вычислений при нахождении детерминанта
|
||||||
|
квадратной матрицы. Были реализованы два алгоритма:
|
||||||
|
|
||||||
|
1. **Последовательный алгоритм**: рекурсивное вычисление детерминанта методом разложения по строкам.
|
||||||
|
2. **Параллельный алгоритм**: вычисление детерминанта с использованием многопоточности,
|
||||||
|
где различные миноры матрицы вычисляются в отдельных потоках.
|
||||||
|
|
||||||
|
Целью эксперимента было сравнение времени выполнения последовательного и параллельного алгоритмов для
|
||||||
|
матриц разного размера и с разным количеством потоков.
|
||||||
|
|
||||||
|
## Структура проекта
|
||||||
|
|
||||||
|
Проект состоит из двух файлов с реализацией алгоритмов:
|
||||||
|
|
||||||
|
- regular.go (в папке alg) — рекурсивное вычисление детерминанта методом разложения по строкам.
|
||||||
|
- parallel.go (в папке alg) — вычисление детерминанта с использованием многопоточности,
|
||||||
|
где различные миноры матрицы вычисляются в отдельных потоках.
|
||||||
|
- matrix.go (в папке util) — вспомогательные функции для матриц.
|
||||||
|
- run.go - запуск бенчмарков.
|
||||||
|
|
||||||
|
## Результаты
|
||||||
|
|
||||||
|
### Последовательный алгоритм
|
||||||
|
|
||||||
|
![img.png](images%2Fimg.png)
|
||||||
|
|
||||||
|
| Размер матрицы | Время выполнения |
|
||||||
|
|----------------|------------------|
|
||||||
|
| 7x7 | 525.1µs |
|
||||||
|
| 8x8 | 5.8494ms |
|
||||||
|
| 9x9 | 35.3115ms |
|
||||||
|
|
||||||
|
### Параллельный алгоритм
|
||||||
|
|
||||||
|
![img_1.png](images%2Fimg_1.png)
|
||||||
|
|
||||||
|
| Размер матрицы | Количество потоков | Время выполнения |
|
||||||
|
|----------------|--------------------|------------------|
|
||||||
|
| 7x7 | 2 | 2ms |
|
||||||
|
| 7x7 | 4 | 2.0009ms |
|
||||||
|
| 7x7 | 6 | 1.0002ms |
|
||||||
|
| 7x7 | 8 | 1.9989ms |
|
||||||
|
| 8x8 | 2 | 5.0014ms |
|
||||||
|
| 8x8 | 4 | 21.5145ms |
|
||||||
|
| 8x8 | 6 | 16.3851ms |
|
||||||
|
| 8x8 | 8 | 17.9676ms |
|
||||||
|
| 9x9 | 2 | 65.099ms |
|
||||||
|
| 9x9 | 4 | 115.9553ms |
|
||||||
|
| 9x9 | 6 | 161.408ms |
|
||||||
|
| 9x9 | 8 | 117.4747ms |
|
||||||
|
|
||||||
|
## Анализ полученных данных
|
||||||
|
|
||||||
|
1. **Последовательный алгоритм**:
|
||||||
|
|
||||||
|
Последовательный алгоритм показал ожидаемую тенденцию: с увеличением размера матрицы, время выполнения
|
||||||
|
увеличивается экспоненциально. Это связано с тем, что сложность рекурсивного алгоритма вычисления
|
||||||
|
детерминанта составляет O(n!), где n — размер матрицы. Даже небольшое увеличение размера матрицы
|
||||||
|
приводит к значительному росту времени вычислений.
|
||||||
|
2. **Параллельный алгоритм**:
|
||||||
|
|
||||||
|
**Матрицы 7x7**:
|
||||||
|
- Время параллельного алгоритма оказалось больше, чем последовательного.
|
||||||
|
Это связано с тем, что накладные расходы на создание потоков, синхронизацию данных и распределение
|
||||||
|
задач превышают выгоду от параллельного выполнения для небольших задач. Матрица 7x7 слишком мала,
|
||||||
|
чтобы эффективно распределить вычисления между потоками, поэтому многопоточность не дает прироста в
|
||||||
|
производительности.
|
||||||
|
|
||||||
|
**Матрицы 8x8**:
|
||||||
|
- Параллельное вычисление снова оказалось медленнее последовательного. Время выполнения с увеличением
|
||||||
|
количества потоков увеличивалось вплоть до 4 потоков, что демонстрирует отрицательный эффект от
|
||||||
|
создания избыточного числа потоков для задач такого размера. Наибольшее ускорение удалось достичь с 2 и 6 потоками,
|
||||||
|
но даже в этом случае результат (5.0014 и 16.3851 ms) был хуже и менее стабильным последовательного (5.8494 ms).
|
||||||
|
|
||||||
|
**Матрицы 9x9**:
|
||||||
|
- Здесь также наблюдается значительное замедление при увеличении количества потоков. Время с 8 потоками
|
||||||
|
составило 117.4747 ms, что все равно больше времени последовательного алгоритма (35.3115 ms). Это связано с тем,
|
||||||
|
что при увеличении числа потоков на задаче, где каждая операция по вычислению минора требует больших
|
||||||
|
вычислительных затрат, накладные расходы на управление потоками могут стать слишком велики.
|
||||||
|
|
||||||
|
## Демонстрационное видео
|
||||||
|
|
||||||
|
Видеозапись доступна по адресу: [https://vk.com/video193898050_456240874](https://vk.com/video193898050_456240874)
|
47
zhimolostnova_anna_lab_6/alg/parallel.go
Normal file
47
zhimolostnova_anna_lab_6/alg/parallel.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package alg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"zhimolostnova_anna_lab_6/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeterminantParallel(matrix [][]float64, workers int) float64 {
|
||||||
|
size := len(matrix)
|
||||||
|
|
||||||
|
if size == 1 {
|
||||||
|
return matrix[0][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if size == 2 {
|
||||||
|
return matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
det := 0.0
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
mu := sync.Mutex{}
|
||||||
|
chunks := size / workers
|
||||||
|
if chunks == 0 {
|
||||||
|
chunks = 1
|
||||||
|
}
|
||||||
|
for j := 0; j < size; j += chunks {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(jStart int) {
|
||||||
|
defer wg.Done()
|
||||||
|
localDet := 0.0
|
||||||
|
for jj := jStart; jj < jStart+chunks && jj < size; jj++ {
|
||||||
|
subMatrix := util.GetMinor(matrix, jj)
|
||||||
|
sign := 1
|
||||||
|
if jj%2 != 0 {
|
||||||
|
sign = -1
|
||||||
|
}
|
||||||
|
localDet += float64(sign) * matrix[0][jj] * DeterminantParallel(subMatrix, workers)
|
||||||
|
}
|
||||||
|
mu.Lock()
|
||||||
|
det += localDet
|
||||||
|
mu.Unlock()
|
||||||
|
}(j)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
return det
|
||||||
|
}
|
30
zhimolostnova_anna_lab_6/alg/regular.go
Normal file
30
zhimolostnova_anna_lab_6/alg/regular.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package alg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"zhimolostnova_anna_lab_6/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Determinant Функция для вычисления детерминанта матрицы
|
||||||
|
func Determinant(matrix [][]float64) float64 {
|
||||||
|
size := len(matrix)
|
||||||
|
|
||||||
|
if size == 1 {
|
||||||
|
return matrix[0][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if size == 2 {
|
||||||
|
return matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Рекурсивное вычисление детерминанта по разложению по первой строке
|
||||||
|
det := 0.0
|
||||||
|
for j := 0; j < size; j++ {
|
||||||
|
subMatrix := util.GetMinor(matrix, j)
|
||||||
|
sign := 1
|
||||||
|
if j%2 != 0 {
|
||||||
|
sign = -1
|
||||||
|
}
|
||||||
|
det += float64(sign) * matrix[0][j] * Determinant(subMatrix)
|
||||||
|
}
|
||||||
|
return det
|
||||||
|
}
|
BIN
zhimolostnova_anna_lab_6/images/img.png
Normal file
BIN
zhimolostnova_anna_lab_6/images/img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
zhimolostnova_anna_lab_6/images/img_1.png
Normal file
BIN
zhimolostnova_anna_lab_6/images/img_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
52
zhimolostnova_anna_lab_6/run.go
Normal file
52
zhimolostnova_anna_lab_6/run.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
"zhimolostnova_anna_lab_6/alg"
|
||||||
|
"zhimolostnova_anna_lab_6/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Функция для бенчмарка последовательного вычисления детерминанта
|
||||||
|
func benchmarkDeterminantSequential(sizes []int) {
|
||||||
|
for _, size := range sizes {
|
||||||
|
matrix := util.GenerateMatrix(size)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
_ = alg.Determinant(matrix)
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
|
||||||
|
fmt.Printf("Sequential determinant of matrix %sx%s took %s\n", strconv.Itoa(size), strconv.Itoa(size), elapsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Функция для бенчмарка параллельного вычисления детерминанта
|
||||||
|
func benchmarkDeterminantParallel(sizes []int, threadsList []int) {
|
||||||
|
for _, size := range sizes {
|
||||||
|
for _, threads := range threadsList {
|
||||||
|
matrix := util.GenerateMatrix(size)
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
_ = alg.DeterminantParallel(matrix, threads)
|
||||||
|
elapsed := time.Since(start)
|
||||||
|
|
||||||
|
fmt.Printf("Parallel determinant of matrix %sx%s with %d threads took %s\n", strconv.Itoa(size), strconv.Itoa(size), threads, elapsed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Список размерностей матриц
|
||||||
|
sizes := []int{7, 8, 9}
|
||||||
|
|
||||||
|
// Список количества потоков для тестирования
|
||||||
|
threadsList := []int{2, 4, 6, 8}
|
||||||
|
|
||||||
|
// Запуск бенчмарков
|
||||||
|
fmt.Println("Sequential Benchmark:")
|
||||||
|
benchmarkDeterminantSequential(sizes)
|
||||||
|
|
||||||
|
fmt.Println("\nParallel Benchmark:")
|
||||||
|
benchmarkDeterminantParallel(sizes, threadsList)
|
||||||
|
}
|
36
zhimolostnova_anna_lab_6/util/matrix.go
Normal file
36
zhimolostnova_anna_lab_6/util/matrix.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import "math/rand"
|
||||||
|
|
||||||
|
// GetMinor Получение минора матрицы
|
||||||
|
func GetMinor(matrix [][]float64, col int) [][]float64 {
|
||||||
|
size := len(matrix)
|
||||||
|
minor := make([][]float64, size-1)
|
||||||
|
for i := range minor {
|
||||||
|
minor[i] = make([]float64, size-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 1; i < size; i++ {
|
||||||
|
subCol := 0
|
||||||
|
for j := 0; j < size; j++ {
|
||||||
|
if j == col {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
minor[i-1][subCol] = matrix[i][j]
|
||||||
|
subCol++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minor
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateMatrix Генерация случайной матрицы размера size x size
|
||||||
|
func GenerateMatrix(size int) [][]float64 {
|
||||||
|
matrix := make([][]float64, size)
|
||||||
|
for i := range matrix {
|
||||||
|
matrix[i] = make([]float64, size)
|
||||||
|
for j := range matrix[i] {
|
||||||
|
matrix[i][j] = float64(rand.Intn(6))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matrix
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user