mapreduce
может быть намного медленнее, чем эквивалентный цикл for
. Небольшой ( реальный ) пример:
function dsum(A::Matrix)
z = zero(A[1,1])
n = Base.LinAlg.checksquare(A)
B = Vector{typeof(z)}(n)
<strong i="9">@inbounds</strong> for j in 1:n
B[j] = mapreduce(k -> A[j,k]*A[k,j], +, z, 1:j)
end
B
end
function dfor(A::Matrix)
z = zero(A[1,1])
n = Base.LinAlg.checksquare(A)
B = Vector{typeof(z)}(n)
<strong i="10">@inbounds</strong> for j in 1:n
d = z
for k in 1:j
d += A[j,k]*A[k,j]
end
B[j] = d
end
B
end
A = randn(127,127)
time(median(<strong i="11">@benchmark</strong> dsum(A)))/time(median(<strong i="12">@benchmark</strong> dfor(A)))
дает мне коэффициент производительности около x50 на Julia 0.5, juliabox.com. Я думаю, это может быть потому, что for
-loop может быть автоматически simd
, а mapreduce - нет? Когда A = randn(N,N)
и N
равно 16
, разрыв составляет около x75, а для N = 10000
разрыв составляет около x25. Замена доступа к массиву A[j,k]
на A[rand(1:size(A,1)),rand(1:size(A,2))]
снижает производительность на обоих, но соотношение становится x1.
simd
причиной того, что один из них в 50 раз быстрее?mapreduce
лежит в основе sum
, так что это может быть популярная ловушка, которая в настоящее время не упоминается.(Сравнивая циклы mapreduce
и циклы for
без доступа к массиву, я все еще вижу разрыв в производительности x2. Например, mapreduce(identity, +, 0, i for i in 1:n)
по сравнению с эквивалентным циклом целочисленного суммирования for
. Похоже, раньше этот разрыв был меньше ? Стоит ли еще один бенчмарк в CI?)
Похоже на дубликат https://github.com/JuliaLang/julia/issues/15276.
Делает:
function dsum(A::Matrix)
z = zero(A[1,1])
n = Base.LinAlg.checksquare(A)
B = Vector{typeof(z)}(n)
<strong i="8">@inbounds</strong> for j::Int in 1:n
B[j] = _help(A, j, z)
end
B
end
_help(A, j, z) = mapreduce(k -> A[j,k]*A[k,j], +, z, 1:j)
дает
julia> time(median(<strong i="12">@benchmark</strong> dsum(A)))/time(median(<strong i="13">@benchmark</strong> dfor(A)))
1.0013213312412255
Вы можете увидеть проблему по @code_warntype
и искать Core.Box
.
+1 за то, что поместил этот тест в BaseBenchmarks; PR там было бы здорово.
Закрытие как дубликат № 15276.
Самый полезный комментарий
+1 за то, что поместил этот тест в BaseBenchmarks; PR там было бы здорово.