mapreduce
pode ser muito mais lento que o for
-loop equivalente. Um pequeno exemplo ( da 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 dá uma taxa de desempenho de cerca de x50 em Julia 0.5, juliabox.com. Eu acho que isso pode ser porque o for
-loop pode ser automaticamente simd
, e o mapreduce não é? Quando A = randn(N,N)
e N
são 16
, a diferença é em torno de x75 e para N = 10000
, a diferença é em torno de x25. Substituir o acesso ao array A[j,k]
por A[rand(1:size(A,1)),rand(1:size(A,2))]
destrói o desempenho em ambos, mas a proporção se torna x1.
simd
é a razão pela qual um é x50 mais rápido?mapreduce
está subjacente sum
, então esta pode ser uma armadilha popular que não é mencionada no momento(Avaliando mapreduce
versus for
-loops sem acesso ao array, ainda vejo uma diferença de desempenho x2. Por exemplo mapreduce(identity, +, 0, i for i in 1:n)
versus o loop for
equivalente de soma inteira. Parece que essa lacuna costumava ser menor ? Vale outro benchmark em CI?)
Parece duplicação de https://github.com/JuliaLang/julia/issues/15276.
Fazendo:
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)
dá
julia> time(median(<strong i="12">@benchmark</strong> dsum(A)))/time(median(<strong i="13">@benchmark</strong> dfor(A)))
1.0013213312412255
Você pode ver o problema por @code_warntype
e procurando por Core.Box
.
+1 por colocar um benchmark disso no BaseBenchmarks; um PR lá seria ótimo.
Fechando como duplicação de #15276.
Comentários muito úteis
+1 por colocar um benchmark disso no BaseBenchmarks; um PR lá seria ótimo.