примитивное умножение матриц
Где я накосячил и как можно улучшить этот код?
Знаю, что в BLAS оно параллелится из коробки, но хотелось руками пощупать, а не готовое использовать.
function multiplyMatrices_oneThreadLoop(A::Matrix{Float64}, B::Matrix{Float64}, N::Int64)
C = zeros(N, N)
Threads.@threads for i in 1:N
for j in 1:N
for k in 1:N
C[i, j]+= A[i, k] * B[k, j]
end
end
end
return C
end
Общие рекомендации сходу: * цикл по строкам всегда быстрее, чем цикл по колонкам (к вопросу о порядке вложенности циклов) * эффективно параллелить можно на количество потоков, не превышающее количество ядер. При этом, каждая задача должна быть достаточно длинной (ориентироваться на 50 мс и больше) * можно отключить проверку границ @inbounds
ну и, кстати, если циклы предполагают заполненине абсолютно всей матрицы С, то C = zeros(N, N) - это избыточная операция инициализации, которая тоже требует время. Лучше просто выделить память при помощи Matrix{Float64}(undef, N, N).
А разве использование undef не приведёт к погрешностям при подсчете C[i, j]?
но там же явная инициализаци C[i, j]+= A[i, k] * B[k, j]
Судя по всему, я напоролся на data-race, так как если использовать undef при инициализации C, то в результирующей матрице начинают появляться NaN'ы
нет, там же в коде +=. Я не заметил это. Тогда оптимальный вариант - считать в отдельную переменную то, что там на цикле с k и однократно записывать в C[i,j]. Заодно уйдёт лишний расчёт косвенных адресов
Обсуждают сегодня