Essa é uma espécie de comparação de desempenho estranha, pois normalmente se mede o tempo necessário para computar algo de substância, em vez de ver quantas iterações triviais se pode fazer em um determinado período de tempo. Como tive problemas para que seus códigos Python e Julia funcionassem, modifiquei o código Julia para funcionar e simplesmente não executei o código Python. Conforme observado por @chepner em um comentário, usar now()
e fazer comparações de tempo com DateTime
objetos é bastante caro. A time.time()
função Python apenas retorna um valor de ponto flutuante. Como se vê, há uma função Julia chamada time()
que faz exatamente a mesma coisa:
julia> time()
1.587648091474481e9
Aqui está o momento da sua f()
função original (modificada para funcionar) no meu sistema:
julia> using Dates
julia> function f()
i = 0
t1 = now()
while true
i += 1
if now() - t1 >= Millisecond(1000)
break
end
end
return i
end
f (generic function with 1 method)
julia> f()
4943739
Ele fez quase 5 milhões de iterações antes do tempo acabar. Como eu disse, não fui capaz de executar seu código Python no meu sistema sem mexer muito (o que não me incomodei em fazer). Mas aqui está uma versão do f()
que os usos time()
em vez disso, o que eu vou imaginativamente chamar g()
:
julia> function g()
i = 0
t1 = time()
while true
i += 1
if time() - t1 >= 1
break
end
end
return i
end
g (generic function with 1 method)
julia> g()
36087637
Esta versão fez 36 milhões de iterações. Então, acho que Julia é mais rápida em fazer loop? Yay! Bem, na verdade, o principal trabalho desse loop são as chamadas para time()
... Julia é mais rápida em gerar muitas time()
chamadas!
Por que é estranho cronometrar isso? Como eu disse, a maior parte do trabalho real aqui está chamando time()
. O resto do ciclo realmente não faz nada. Em uma linguagem compilada otimizada, se o compilador vir um loop que não faz nada, ele será eliminado completamente. Por exemplo:
julia> function h()
t = 0
for i = 1:100_000_000
t += i
end
return t
end
h (generic function with 1 method)
julia> h()
5000000050000000
julia> @time h()
0.000000 seconds
5000000050000000
Uau, zero segundos! Como isso é possível? Bem, vejamos o código LLVM (tipo código de máquina semelhante, mas para uma máquina imaginária usada como representação intermediária), que reduz para:
julia> @code_llvm h()
; @ REPL[16]:1 within `h'
define i64 @julia_h_293() {
top:
; @ REPL[16]:6 within `h'
ret i64 5000000050000000
}
O compilador vê o loop, descobre que o resultado é o mesmo todas as vezes e apenas retorna esse valor constante em vez de realmente executar o loop. O que, é claro, leva tempo zero.