Использование параллельного программирования

Цель работы

Научиться использовать многопроцессность как основу параллельного программирования с помощью модуля multiprocessing

Задания для выполнения

  1. Написать программу, перемножающую две матрицы поэлементно. Элементы матрицы-произведения должны вычисляться в несколько потоков.
  2. Программа должна читать две матрицы из исходных файлов. Матрица-произведение также должна записываться в файл.
  3. Используйте пул процессов, чтобы распределять вычисления между определенным заранее количеством процессов, не зависящим от размеров матрицы.
  4. Модифицируйте программу, чтобы элементы результирующей матрицы записывались в промежуточный файл сразу по факту их вычисления.

Методические указания

Довольно часто при решении прикладных задач приходится выполнять тяжелые математические расчеты. Такие расчеты могут занимать много времени и естественно желание ускорить работу программы, распараллелив вычисления на несколько ядер процессора. Точно такой же подход используется и в высокопроизводительных системах при распараллеливании несколько узлов вычислительного кластера.

Для начала нужно понять, какой аспект этой задачи можно распараллеливать. При перемножении матриц для вычисления определенного элемента совершенно не обязательно знать результат вычисления других элементов. Поэтому, каждый элемент можно вычислить независимо от других.

Matrix multiplication

Для того, чтобы выделить участок кода в поток, выделим его в функцию. То есть, нам надо написать функцию, которая вычисляет один определенный элемент матрицы. Для этого необходимо знать индекс этого элемента, и исходные матрицы:

def element(index, A, B, res):
    glodal res
    i, j = index
    res = 0
    # get a middle dimension
    N = len(A[0]) or len(B)
    for k in range(N):
        res += A[i][k] * B[k][j]
    return res

Для использования многопроцессности необходимо импортировать соответствующий модуль:

from multiprocessing import Process, Pool

Теперь мы можем создать новый процесс и запустить в нем вычисление отдельного элемента матрицы.

res = 0

p1 = Process(target=element, args=[(0, 0), matrix1, matrix2, res])
p1.start()
p1.join()

print(res)

Осталось только придумать легкий способ запустить на выполнение вычисление всех элементов матрицы.

Дополнительные задания

  1. Модифицируйте программу таким образом, чтобы она сама определяла количество необходимых параллельных потоков.
  2. Модифицируйте программу таким образом, чтобы одна часть программы генерировала случайные квадратные матрицы заданной размерности, а другая - перемножала их по мере генерации. Протестируйте асинхронность работы программы. Реализуйте механизм остановки процесса перемножения.