anisin_ruslan_lab_6 is ready
This commit is contained in:
9
anisin_ruslan_lab_6/Dockerfile
Normal file
9
anisin_ruslan_lab_6/Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
||||
FROM golang:alpine3.22
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY main.go .
|
||||
|
||||
RUN go build -o matrix-det main.go
|
||||
|
||||
ENTRYPOINT ["./matrix-det"]
|
||||
62
anisin_ruslan_lab_6/README.md
Normal file
62
anisin_ruslan_lab_6/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Лабораторная работа №6
|
||||
|
||||
## Использованные технологии
|
||||
|
||||
- Go
|
||||
|
||||
## Что делает
|
||||
|
||||
Нахождит детерминант квадратной матрицы (последовательно или параллельно)
|
||||
|
||||
## Запуск
|
||||
|
||||
Программа работает в двух режимах: **Normal** (обычный) и **Benchmark** (тестирование производительности). Режим переключается флагом `-mode`.
|
||||
|
||||
### 1. Обычный режим (по умолчанию)
|
||||
|
||||
Позволяет вручную задать размер матрицы и количество потоков.
|
||||
|
||||
**Флаги:**
|
||||
- `-size`: Размер квадратной матрицы (N x N). По умолчанию: 300.
|
||||
- `-threads`: Количество потоков (горутин). По умолчанию: 4.
|
||||
|
||||
### 2. Режим бенчмарка
|
||||
|
||||
Автоматически запускает серию тестов для матриц размером 100x100, 300x300 и 500x500 с различным количеством потоков (1, 2, 4, 6, 8, 12).
|
||||
|
||||
1. Установите Docker.
|
||||
2. Клонируйте репозиторий.
|
||||
3. В терминале перейдите в папку anisin_ruslan_lab_5 и выполните команду:
|
||||
```bash
|
||||
docker build -t matrix-det .
|
||||
```
|
||||
4. Примеры возможных комманды для запуска представлены ниже:
|
||||
|
||||
**Запуск с параметрами по умолчанию:**
|
||||
```bash
|
||||
docker run --rm matrix-det
|
||||
```
|
||||
|
||||
**Обычный режим (свои параметры):**
|
||||
```bash
|
||||
docker run --rm matrix-det -size=500 -threads=8
|
||||
```
|
||||
|
||||
**Режим бенчмарка:**
|
||||
```bash
|
||||
docker run --rm matrix-det -mode=benchmark
|
||||
```
|
||||
### Результат запуска в режиме бенчмарка
|
||||

|
||||
|
||||
## Анализ результатов
|
||||
|
||||
**100x100:** Результаты крайне нестабильны. Использование 12 потоков сделало работу в 2 раза медленнее (1.45ms), чем в 1 поток (0.6ms). Накладные расходы на синхронизацию здесь вредны.
|
||||
**300x300:** Пик эффективности достигнут на 4 потоках (4.9ms). Дальнейшее увеличение числа потоков только ухудшает результат, возвращая время к показателям однопоточного режима.
|
||||
**500x500:** Лучший результат сместился на 6 потоков (18.8ms, ускорение более чем в 2 раза), однако 8 и 12 потоков снова показывают падение производительности.
|
||||
|
||||
**Вывод:** В отличие от умножения матриц, алгоритм требует остановки и синхронизации всех потоков после обработки каждого столбца. Слишком большое количество потоков создает высокие накладные расходы на ожидание. Оптимально использовать 4-6 потоков.
|
||||
|
||||
## Видео
|
||||
|
||||
[Ссылка](https://drive.google.com/file/d/1F7ZW6GayRJe_n7auAdlZw_MzUDwPrjP5/view)
|
||||
BIN
anisin_ruslan_lab_6/benchmark_result.png
Normal file
BIN
anisin_ruslan_lab_6/benchmark_result.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
3
anisin_ruslan_lab_6/go.mod
Normal file
3
anisin_ruslan_lab_6/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module anisin_ruslan_lab_6
|
||||
|
||||
go 1.24.4
|
||||
156
anisin_ruslan_lab_6/main.go
Normal file
156
anisin_ruslan_lab_6/main.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Matrix [][]int
|
||||
|
||||
func GenerateMatrix(n int) Matrix {
|
||||
m := make(Matrix, n)
|
||||
for i := 0; i < n; i++ {
|
||||
m[i] = make([]int, n)
|
||||
for j := 0; j < n; j++ {
|
||||
m[i][j] = rand.Intn(10)
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
func CalculateDeterminant(m Matrix, workers int) float64 {
|
||||
n := len(m)
|
||||
|
||||
temp := make([][]float64, n)
|
||||
for i := 0; i < n; i++ {
|
||||
temp[i] = make([]float64, n)
|
||||
for j := 0; j < n; j++ {
|
||||
temp[i][j] = float64(m[i][j])
|
||||
}
|
||||
}
|
||||
|
||||
detSign := 1.0
|
||||
|
||||
for k := 0; k < n; k++ {
|
||||
pivotIndex := k
|
||||
maxVal := math.Abs(temp[k][k])
|
||||
for i := k + 1; i < n; i++ {
|
||||
if math.Abs(temp[i][k]) > maxVal {
|
||||
maxVal = math.Abs(temp[i][k])
|
||||
pivotIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
if math.Abs(temp[pivotIndex][k]) < 1e-9 {
|
||||
return 0
|
||||
}
|
||||
|
||||
if pivotIndex != k {
|
||||
temp[k], temp[pivotIndex] = temp[pivotIndex], temp[k]
|
||||
detSign = -detSign
|
||||
}
|
||||
|
||||
rowsToProcess := n - (k + 1)
|
||||
if rowsToProcess <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if workers == 1 || rowsToProcess < workers {
|
||||
for i := k + 1; i < n; i++ {
|
||||
processRow(temp, n, k, i)
|
||||
}
|
||||
} else {
|
||||
var wg sync.WaitGroup
|
||||
rowsPerWorker := (rowsToProcess + workers - 1) / workers
|
||||
|
||||
startIndex := k + 1
|
||||
|
||||
for w := 0; w < workers; w++ {
|
||||
start := startIndex + w*rowsPerWorker
|
||||
end := start + rowsPerWorker
|
||||
if start >= n {
|
||||
break
|
||||
}
|
||||
if end > n {
|
||||
end = n
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(s, e int) {
|
||||
defer wg.Done()
|
||||
for i := s; i < e; i++ {
|
||||
processRow(temp, n, k, i)
|
||||
}
|
||||
}(start, end)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
det := 1.0
|
||||
for i := 0; i < n; i++ {
|
||||
det *= temp[i][i]
|
||||
}
|
||||
return det * detSign
|
||||
}
|
||||
|
||||
func processRow(m [][]float64, n, pivotIdx, rowIdx int) {
|
||||
factor := m[rowIdx][pivotIdx] / m[pivotIdx][pivotIdx]
|
||||
for j := pivotIdx; j < n; j++ {
|
||||
m[rowIdx][j] -= factor * m[pivotIdx][j]
|
||||
}
|
||||
}
|
||||
|
||||
func runOnce(size, workers int) time.Duration {
|
||||
A := GenerateMatrix(size)
|
||||
runtime.GC()
|
||||
start := time.Now()
|
||||
_ = CalculateDeterminant(A, workers)
|
||||
return time.Since(start)
|
||||
}
|
||||
|
||||
func runBenchmarkMode() {
|
||||
sizes := []int{100, 300, 500}
|
||||
threadCounts := []int{1, 2, 4, 6, 8, 12}
|
||||
|
||||
for i, size := range sizes {
|
||||
for _, workers := range threadCounts {
|
||||
duration := runOnce(size, workers)
|
||||
fmt.Printf("Size: %d Threads: %d Time: %v\n", size, workers, duration)
|
||||
}
|
||||
if i < len(sizes)-1 {
|
||||
fmt.Println("---")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func runNormalMode(size, workers int) {
|
||||
fmt.Printf("Generating matrix %dx%d...\n", size, size)
|
||||
A := GenerateMatrix(size)
|
||||
|
||||
fmt.Printf("Calculating determinant using %d threads...\n", workers)
|
||||
start := time.Now()
|
||||
det := CalculateDeterminant(A, workers)
|
||||
duration := time.Since(start)
|
||||
|
||||
fmt.Printf("Determinant: %.4g\n", det)
|
||||
fmt.Printf("Done. Time elapsed: %v\n", duration)
|
||||
}
|
||||
|
||||
func main() {
|
||||
mode := flag.String("mode", "normal", "Mode: 'normal' or 'benchmark'")
|
||||
size := flag.Int("size", 300, "Matrix size (for normal mode)")
|
||||
threads := flag.Int("threads", 4, "Number of threads (for normal mode)")
|
||||
flag.Parse()
|
||||
|
||||
if *mode == "benchmark" {
|
||||
runBenchmarkMode()
|
||||
} else {
|
||||
runNormalMode(*size, *threads)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user