mapreduce
puede ser mucho más lento que el ciclo equivalente for
. Un pequeño ejemplo ( de la vida real ):
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)))
me da una relación de rendimiento de aproximadamente x50 en Julia 0.5, juliabox.com. Creo que esto podría deberse a que el bucle for
puede ser automáticamente simd
, y el mapreduce no lo es. Cuando A = randn(N,N)
y N
es 16
, la brecha es de alrededor de x75, y para N = 10000
, la brecha es de alrededor de x25. Reemplazar el acceso a la matriz A[j,k]
con A[rand(1:size(A,1)),rand(1:size(A,2))]
destruye el rendimiento en ambos, pero la proporción se vuelve x1.
simd
la razón por la que uno es x50 más rápido?mapreduce
subyace sum
, por lo que podría ser una trampa popular que no se menciona actualmente(Comparando mapreduce
versus for
-bucles sin acceso a la matriz, todavía veo una brecha de rendimiento x2. Por ejemplo mapreduce(identity, +, 0, i for i in 1:n)
versus el bucle equivalente de suma de enteros for
. Parece que esta brecha solía ser más pequeña (¿Vale la pena otro punto de referencia en CI?)
Parece una copia de https://github.com/JuliaLang/julia/issues/15276.
Haciendo:
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)
da
julia> time(median(<strong i="12">@benchmark</strong> dsum(A)))/time(median(<strong i="13">@benchmark</strong> dfor(A)))
1.0013213312412255
Puede ver el problema por @code_warntype
y buscando Core.Box
.
+1 por poner un punto de referencia de esto en BaseBenchmarks; un PR allí sería genial.
Cerrando como duplicado de #15276.
Comentario más útil
+1 por poner un punto de referencia de esto en BaseBenchmarks; un PR allí sería genial.