Comparação de velocidade entre Python e Julia

9

Tentei comparar esses dois trechos e ver quantas iterações poderiam ser feitas em um segundo. Acontece que Julia atinge 2,5 milhões de iterações, enquanto Python, 4 milhões. Julia não deveria ser mais rápida. Ou talvez esses dois trechos não sejam equivalentes?

Pitão:

t1 = time.time()
i = 0
while True:
    i += 1
    if time.time() - t1 >= 1:
        break

Julia:

function f()
    i = 0
    t1 = now()
    while true
        i += 1
        if now() - t1 >= Base.Dates.Millisecond(1000)
            break
        end
    end
    return i
end
Michas
fonte
4
Não tenho certeza de como Julia funciona, mas parece que você precisa construir um novo objeto para cada comparação, enquanto o Python faz comparações simples e inteiras.
chepner 23/04
11
Observe também que essa é uma comparação de velocidade de homem pobre, não é? Atualmente, você pode fazer o Python e a Julia rodarem aproximadamente na mesma velocidade com a quantidade adequada de motivação (nas duas extremidades). Se você estiver fazendo isso para escolher um dos idiomas, procure em qual deles é mais fácil pensar. Você pode otimizar isso mais tarde, quando realmente precisar.
norok2 23/04
@ norok2 Isso é verdade para alguns códigos, mas não para outros. Se você conseguir transformar o código Python em uma chamada para uma função de biblioteca escrita em uma linguagem rápida, ou se for suportada por numba, ou algo semelhante, talvez seja, mas, caso contrário, o Python será significativamente mais lento.
DNF
@DNF Há algumas coisas em que Python é mais rápido e outras em que Julia é mais rápida. Tenho certeza que você pode encontrar exemplos de ambos. É ignorar excessivamente a imagem completa dizer que o Python é "significativamente" (o que quer que isso possa significar) mais lento apenas por causa das chamadas explícitas e de funções explícitas e relativamente caras. Claro, se esse é o seu cavalo de trabalho, talvez você esteja melhor com Julia. No entanto, se você usar as ferramentas certas, poderá ser igualmente rápido no Python. Vale a pena aprender essas ferramentas ou é melhor aprender um idioma diferente. É difícil dizer.
norok2 23/04
11
Eu uso os dois idiomas e, embora existam 'alguns' exemplos de ambos serem mais rápidos, o equilíbrio está consideravelmente de um lado. É simplesmente uma consequência do Python ser interpretado e dificilmente focado no desempenho, enquanto Julia tem um forte foco no desempenho. É realmente muito como dizer que Python é tão rápido como C. Seria muito estranho se lá não era uma diferença significativa, e minaria a maior parte do propósito de Julia.
DNF

Respostas:

9

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 DateTimeobjetos é 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.

StefanKarpinski
fonte
É o BogoMips das linguagens de programação
norok2 23/04
11
Certo, mas bogomips são usados ​​para medir a CPU, não a linguagem de programação. Mas claro, é algo que se pode medir.
StefanKarpinski 23/04
4

Você provavelmente deseja usar a time_nsfunção em Julia:

function f()
    i = 0
    t1 = time_ns()
    while true
        i += 1
        if time_ns() - t1 >= 10^9
            break
        end
    end
    return i
end

No meu computador, ele roda 10 vezes mais rápido que o Python.

Bogumił Kamiński
fonte
4

Bem, não é isso que observo no meu sistema:

Python 3.7.7

Python 3.7.7 (default, Mar 26 2020, 15:48:22) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.4.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import time                                                                                                                                                       

In [2]: def f(): 
   ...:     t1 = time.time() 
   ...:     i = 0 
   ...:     while True: 
   ...:         i += 1 
   ...:         if time.time() - t1 >= 1: 
   ...:             return i 
   ...:                                                                                                                                                                   

In [3]: f()                                                                                                                                                               
Out[3]: 4676268


Julia 1.4.0:

julia> using Dates

julia> function f()
           i = 0
           t1 = now()
           while true
               i += 1
               if now() - t1 >= Dates.Millisecond(1000)
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
6339528

mas observe que o simples uso time(ou seja, comparação de números simples) é ainda mais rápido:

julia> function f()
           i = 0
           t1 = time()
           while true
               i += 1
               if time() - t1 >= 1
                   break
               end
           end
           return i
       end
f (generic function with 1 method)

julia> f()
24742703
François Févotte
fonte
você não deveria usar time.perf_counter_ns() em Python?
norok2 23/04
Usar time.perf_counter_ns não altera nada (pelo menos no meu sistema) para este benchmark. Eu acho que, ao medir diferenças de tempo na ordem de 1 segundo, a precisão da medição do tempo não importa muito. Somente o tempo necessário para realizar a medição e comparar os objetos resultantes é importante aqui (assim como a eficiência dos próprios loops).
François Févotte 23/04
Em Julia questões de tempo de medição - é por isso que no meu código que eu usei time_nsnão timecomo é ~ 30% mais rápido, então.
Bogumił Kamiński