Confronto velocità Python vs Julia


9

Ho provato a confrontare questi due frammenti e vedere quante iterazioni si potrebbero fare in un secondo. Si scopre che Julia raggiunge 2,5 milioni di iterazioni mentre Python 4 milioni. Julia non dovrebbe essere più veloce. O forse questi due frammenti non sono equivalenti?

Pitone:

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

Giulia:

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

4
Non sono sicuro di come funzioni Julia, ma sembra che tu debba costruire un nuovo oggetto per ogni confronto, mentre Python sta facendo dei semplici confronti interi.
Chepner,

1
Inoltre, tieni presente che questo è un po 'il confronto della velocità dell'uomo povero, vero? Al giorno d'oggi puoi far funzionare Python e Julia alla stessa velocità con la giusta quantità di motivazione (su entrambe le estremità). Se lo stai facendo per imparare una delle lingue, guarda in quale è più facile pensare. Puoi ottimizzarlo in seguito, quando ne hai davvero bisogno.
norok2

@ norok2 Questo è vero per alcuni codici ma non per altri. Se sei in grado di trasformare il codice Python in una chiamata a una funzione di libreria scritta in un linguaggio veloce, o se è supportato da numba o qualcosa di simile, allora forse, ma per il resto Python è significativamente più lento.
DNF

@DNF Ci sono alcune cose in cui Python è più veloce e altre in cui Julia è più veloce. Sono sicuro che puoi trovare esempi di entrambi. Ignora eccessivamente il quadro completo affermare che Python è "significativamente" (qualunque cosa ciò significhi) più lento solo a causa del loop esplicito relativamente costoso e delle chiamate di funzione. Certo, se quello è il tuo cavallo da lavoro di quello che forse stai meglio con Julia. Tuttavia, se usi gli strumenti giusti, puoi essere altrettanto veloce in Python. Vale la pena di imparare questi strumenti o è meglio imparare una lingua diversa. È difficile da dire.
norok2

1
Uso entrambe le lingue e, sebbene ci siano "alcuni" esempi di entrambe le velocità, l'equilibrio è considerevolmente da un lato. È semplicemente una conseguenza del fatto che Python viene interpretato e non si concentra affatto sulle prestazioni, mentre Julia si concentra fortemente sulle prestazioni. In realtà è molto simile a dire che Python è veloce come C. Sarebbe molto strano se non ci fosse una differenza significativa, e minerebbe gran parte dello scopo di Julia.
DNF

Risposte:


9

Questo è un tipo di confronto delle prestazioni strano dal momento che in genere si misura il tempo necessario per calcolare qualcosa di sostanziale, piuttosto che vedere quante banali iterazioni si possono fare in un determinato periodo di tempo. Ho avuto problemi a far funzionare i tuoi codici Python e Julia, quindi ho modificato il codice Julia per funzionare e non ho eseguito il codice Python. Come notato da @chepner in un commento, l'uso now()e il confronto dei tempi con gli DateTimeoggetti è piuttosto costoso. La time.time()funzione Python restituisce solo un valore in virgola mobile. A quanto pare, c'è una funzione Julia chiamata time()che fa esattamente la stessa cosa:

julia> time()
1.587648091474481e9

Ecco i tempi della tua f()funzione originale (modificata per funzionare) sul mio 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

Ha fatto quasi 5 milioni di iterazioni prima dello scadere del tempo. Come ho detto, non sono stato in grado di ottenere il tuo codice Python per essere eseguito sul mio sistema senza una significativa manipolazione (cosa che non mi sono preoccupato di fare). Ma ecco una versione f()che utilizza time()invece, che chiamerò immaginativamente 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

Questa versione ha fatto 36 milioni di iterazioni. Quindi immagino che Julia sia più veloce nel looping? Sìì! Bene, in realtà il lavoro principale in questo ciclo sono le chiamate a time()così ... Julia è più veloce nel generare molte time()chiamate!

Perché è strano cronometrare questo? Come ho detto, la maggior parte del lavoro reale qui sta chiamando time(). Il resto del ciclo non fa davvero nulla. In un linguaggio compilato ottimizzante, se il compilatore vede un ciclo che non fa nulla, lo eliminerà del tutto. Per esempio:

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    

Woah, zero secondi! Come è possibile? Bene, diamo un'occhiata al codice LLVM (tipo di codice macchina simile ma per una macchina immaginaria che viene utilizzata come rappresentazione intermedia) questo si riduce a:

julia> @code_llvm h()

;  @ REPL[16]:1 within `h'
define i64 @julia_h_293() {
top:
;  @ REPL[16]:6 within `h'
  ret i64 5000000050000000
}

Il compilatore vede il ciclo, scopre che il risultato è lo stesso ogni volta e restituisce quel valore costante invece di eseguire effettivamente il ciclo. Che, ovviamente, richiede zero tempo.


È il BogoMips dei linguaggi di programmazione
norok2

1
Giusto, ma i bogomips sono usati per misurare la CPU, non il linguaggio di programmazione. Ma certo, è una cosa che si può misurare.
StefanKarpinski,

4

Probabilmente vuoi usare la time_nsfunzione in Julia:

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

Sul mio computer funziona 10 volte più veloce di Python.


4

Bene, non è quello che osservo sul mio 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

ma nota che usare semplicemente time(cioè confrontare numeri semplici) è ancora più veloce:

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

non dovresti usare time.perf_counter_ns()in Python?
norok2

L'uso di time.perf_counter_ns non cambia nulla (almeno sul mio sistema) per questo benchmark. Immagino che, quando si misurano le differenze di tempo nell'ordine di 1 secondo, l'accuratezza della misurazione del tempo non conta molto. Solo il tempo necessario per eseguire la misurazione e confrontare gli oggetti risultanti è importante qui (così come l'efficienza dei loop stessi).
François Févotte,

In Julia questioni relative all'ora di misura - è per questo che nel mio codice che ho usato time_nsnon timecome è ~ 30% più veloce.
Bogumił Kamiński,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.