forked from Alexey/DAS_2024_1
lab 6 complete
This commit is contained in:
parent
131dc39f6c
commit
20a39fa9a5
87
zhimolostnova_anna_lab_6/README.md
Normal file
87
zhimolostnova_anna_lab_6/README.md
Normal file
@ -0,0 +1,87 @@
|
||||
# Отчет по лабораторной работе №5
|
||||
|
||||
## Описание задачи
|
||||
|
||||
Данная работа нацелена на изучение эффективности параллельных вычислений при нахождении детерминанта
|
||||
квадратной матрицы. Были реализованы два алгоритма:
|
||||
|
||||
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