Merge pull request 'kashin_maxim_lab_5' (#124) from kashin_maxim_lab_5 into main
Reviewed-on: #124
This commit is contained in:
commit
528309ab84
62
kashin_maxim_lab_5/main.py
Normal file
62
kashin_maxim_lab_5/main.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
import multiprocessing
|
||||||
|
import numpy as np
|
||||||
|
import time
|
||||||
|
|
||||||
|
def sequential_multiply(A, B):
|
||||||
|
# Последовательное умножение матриц
|
||||||
|
return np.dot(A, B)
|
||||||
|
|
||||||
|
def parallel_multiply(A, B, num_processes):
|
||||||
|
rows_A = A.shape[0]
|
||||||
|
cols_B = B.shape[1]
|
||||||
|
|
||||||
|
# Используем Array для совместного использования памяти
|
||||||
|
C = multiprocessing.Array('d', rows_A * cols_B) # 'd' для double
|
||||||
|
|
||||||
|
chunk_size = int(rows_A / num_processes)
|
||||||
|
processes = []
|
||||||
|
|
||||||
|
for i in range(num_processes):
|
||||||
|
start = chunk_size * i
|
||||||
|
end = chunk_size * (i + 1) if i < num_processes - 1 else rows_A
|
||||||
|
|
||||||
|
# Запускаем процесс для умножения
|
||||||
|
p = multiprocessing.Process(target=perform_multiplication, args=(A, B, C, start, end, rows_A, cols_B))
|
||||||
|
processes.append(p)
|
||||||
|
p.start()
|
||||||
|
|
||||||
|
for p in processes:
|
||||||
|
p.join()
|
||||||
|
|
||||||
|
# Преобразуем C в 2D массив NumPy для удобства
|
||||||
|
return np.frombuffer(C.get_obj()).reshape((rows_A, cols_B))
|
||||||
|
|
||||||
|
def perform_multiplication(A, B, C, start, end, rows_A, cols_B):
|
||||||
|
# Умножение строк матрицы A на столбцы матрицы B
|
||||||
|
for i in range(start, end):
|
||||||
|
for j in range(cols_B):
|
||||||
|
C[i * cols_B + j] = np.dot(A[i, :], B[:, j])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
matrix_sizes = [100, 300, 500]
|
||||||
|
num_processes = int(input('Введите количество потоков: '))
|
||||||
|
|
||||||
|
for n in matrix_sizes:
|
||||||
|
# Генерация случайных матриц A и B
|
||||||
|
A = np.random.randint(10, size=(n, n))
|
||||||
|
B = np.random.randint(10, size=(n, n))
|
||||||
|
|
||||||
|
# Бенчмарк для последовательного умножения
|
||||||
|
start = time.time()
|
||||||
|
sequential_result = sequential_multiply(A, B)
|
||||||
|
end = time.time()
|
||||||
|
print(f"Последовательное умножение {n}x{n}: {end - start:.6f} секунд")
|
||||||
|
|
||||||
|
# Бенчмарк для параллельного умножения
|
||||||
|
start = time.time()
|
||||||
|
parallel_result = parallel_multiply(A, B, num_processes)
|
||||||
|
end = time.time()
|
||||||
|
print(f"Параллельное умножение {n}x{n}: {end - start:.6f} секунд")
|
||||||
|
|
||||||
|
# Проверка совпадения результатов
|
||||||
|
assert np.array_equal(sequential_result, parallel_result), "Результаты не совпадают!"
|
99
kashin_maxim_lab_5/readme.md
Normal file
99
kashin_maxim_lab_5/readme.md
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
# Кашин Максим ПИбд-42
|
||||||
|
|
||||||
|
# Отчет по умножению матриц
|
||||||
|
|
||||||
|
## Описание
|
||||||
|
|
||||||
|
В данной лабораторной работе реализованы два алгоритма для умножения больших квадратных матриц: последовательный и параллельный.
|
||||||
|
|
||||||
|
### Алгоритмы
|
||||||
|
|
||||||
|
1. **Последовательное умножение**:
|
||||||
|
- Для умножения используется функция `sequential_multiply`, которая принимает две матрицы \( A \) и \( B \) и возвращает их произведение \( C = A \cdot B \). Умножение реализовано с помощью функции NumPy `np.dot()`.
|
||||||
|
|
||||||
|
2. **Параллельное умножение**:
|
||||||
|
- Для параллельного умножения используется функция `parallel_multiply`, которая делит задачу на несколько процессов, каждый из которых умножает свои строки матрицы \( A \) на матрицу \( B \).
|
||||||
|
- Результат записывается в разделяемый массив `C`, который создается с помощью `multiprocessing.Array`.
|
||||||
|
- Каждому процессу передается диапазон строк, которые он должен обработать.
|
||||||
|
|
||||||
|
### Структура кода
|
||||||
|
|
||||||
|
- **Функции**:
|
||||||
|
- `sequential_multiply(A, B)`: Выполняет последовательное умножение.
|
||||||
|
- `parallel_multiply(A, B, num_processes)`: Выполняет параллельное умножение с заданным количеством процессов.
|
||||||
|
- `perform_multiplication(A, B, C, start, end, rows_A, cols_B)`: Вспомогательная функция, выполняющая умножение строк матрицы.
|
||||||
|
|
||||||
|
## Результаты
|
||||||
|
|
||||||
|
Результаты выполнения программы для разных размеров матриц и количества потоков:
|
||||||
|
|
||||||
|
### Время выполнения для 2 потоков
|
||||||
|
```
|
||||||
|
Введите количество потоков: 2
|
||||||
|
Последовательное умножение 100x100: 0.001003 секунд
|
||||||
|
Параллельное умножение 100x100: 0.900024 секунд
|
||||||
|
Последовательное умножение 300x300: 0.015999 секунд
|
||||||
|
Параллельное умножение 300x300: 1.078092 секунд
|
||||||
|
Последовательное умножение 500x500: 0.096649 секунд
|
||||||
|
Параллельное умножение 500x500: 1.450420 секунд
|
||||||
|
```
|
||||||
|
|
||||||
|
### Время выполнения для 4 потоков
|
||||||
|
```
|
||||||
|
Введите количество потоков: 4
|
||||||
|
Последовательное умножение 100x100: 0.001000 секунд
|
||||||
|
Параллельное умножение 100x100: 1.686326 секунд
|
||||||
|
Последовательное умножение 300x300: 0.015986 секунд
|
||||||
|
Параллельное умножение 300x300: 1.749842 секунд
|
||||||
|
Последовательное умножение 500x500: 0.087000 секунд
|
||||||
|
Параллельное умножение 500x500: 1.960365 секунд
|
||||||
|
```
|
||||||
|
|
||||||
|
### Время выполнения для 8 потоков
|
||||||
|
```
|
||||||
|
Введите количество потоков: 8
|
||||||
|
Последовательное умножение 100x100: 0.000000 секунд
|
||||||
|
Параллельное умножение 100x100: 3.307927 секунд
|
||||||
|
Последовательное умножение 300x300: 0.016013 секунд
|
||||||
|
Параллельное умножение 300x300: 3.321677 секунд
|
||||||
|
Последовательное умножение 500x500: 0.086618 секунд
|
||||||
|
Параллельное умножение 500x500: 3.446928 секунд
|
||||||
|
```
|
||||||
|
|
||||||
|
### Время выполнения для 16 потоков
|
||||||
|
```
|
||||||
|
Введите количество потоков: 16
|
||||||
|
Последовательное умножение 100x100: 0.000000 секунд
|
||||||
|
Параллельное умножение 100x100: 6.534394 секунд
|
||||||
|
Последовательное умножение 300x300: 0.016131 секунд
|
||||||
|
Параллельное умножение 300x300: 6.787100 секунд
|
||||||
|
Последовательное умножение 500x500: 0.086582 секунд
|
||||||
|
Параллельное умножение 500x500: 7.096588 секунд
|
||||||
|
```
|
||||||
|
|
||||||
|
## Анализ результатов
|
||||||
|
|
||||||
|
1. **Сравнение времени выполнения**:
|
||||||
|
- Последовательное умножение показывает значительно более быстрое время выполнения по сравнению с параллельным умножением для всех размеров матриц. Например, при умножении матриц размером 100x100, время последовательного умножения составляет всего 0.001003 секунд, в то время как параллельное умножение занимает 0.900024 секунд при использовании 2 потоков. Это указывает на то, что накладные расходы на создание и управление потоками значительно превышают выгоды от параллельной обработки на малом размере матриц.
|
||||||
|
|
||||||
|
2. **Увеличение размеров матриц**:
|
||||||
|
- Время выполнения параллельного умножения становится менее эффективным по мере увеличения размеров матриц. Например, при умножении матриц размером 500x500 время параллельного умножения увеличивается до 1.450420 секунд при 2 потоках, в то время как последовательное умножение занимает всего 0.096649 секунд. Это происходит из-за того, что при больших размерах матриц накладные расходы на распределение задач между потоками становятся более значительными.
|
||||||
|
|
||||||
|
3. **Влияние количества потоков**:
|
||||||
|
- Увеличение количества потоков также негативно сказывается на времени выполнения параллельного алгоритма. Например, при 4 потоках время выполнения для 100x100 матриц составляет 1.686326 секунд, а при 8 потоках — 3.307927 секунд. Это объясняется тем, что количество потоков, превышающее количество доступных ядер процессора, приводит к дополнительным накладным расходам на переключение контекста между потоками, что замедляет выполнение.
|
||||||
|
|
||||||
|
4. **Эффективность последовательного алгоритма**:
|
||||||
|
- Последовательный алгоритм показывает стабильную производительность, которая не зависит от накладных расходов, связанных с многопоточностью. Он использует оптимизированные алгоритмы NumPy, что также способствует высокой производительности.
|
||||||
|
|
||||||
|
## Выводы
|
||||||
|
|
||||||
|
1. **Эффективность**:
|
||||||
|
- Последовательное умножение матриц показывает значительно более высокую производительность по сравнению с параллельным умножением для малых и средних размеров матриц.
|
||||||
|
- Параллельное умножение начинает терять эффективность при увеличении количества потоков, что может быть связано с накладными расходами на создание процессов и синхронизацию между ними.
|
||||||
|
|
||||||
|
2. **С увеличением размера матриц**:
|
||||||
|
- Время выполнения параллельного алгоритма увеличивается, особенно для больших матриц и большого количества потоков, что указывает на ограниченную эффективность параллельного подхода в данной реализации.
|
||||||
|
|
||||||
|
|
||||||
|
## Ссылка на видео
|
||||||
|
[Видео-отчёт Кашин Максим ПИбд-42](https://disk.yandex.ru/i/0g-KQ5FarFGtqg)
|
Loading…
Reference in New Issue
Block a user