Pagina 1 di 1
[Risolto] [Python/MatLab] Test di velocità
Inviato: sabato 15 aprile 2017, 7:50
da BlueEyes
Sorpresa nell'Uovo di Pasqua ... di domani. Nel test di confronto tra i due linguaggi di programmazione del titolo, riguardante l'uso di quattro cicli nidificati su un'applicazione che utilizzo di frequente e che fa uso della forza bruta per sommare oltre 33 milioni di 'pezzettini' infinitesimali [(M3*M4)^2], ho trovato uno
scarto abissale tra i tempi di esecuzione. In dettaglio:
Codice: Seleziona tutto
1.. MatLab 8.0 tempo= 8 secondi [L=5.5293e-7]
2.. Python 3.5.1 tempo= 102 secondi [L=5.5414e-7]
Conoscendo, per fama, le grandi potenzialità delle librerie Python, mi aspettavo quanto meno dei tempi dello stesso ordine di grandezza, non uno di una quindicina di volte più lento dell'altro. L'idea che mi son fatta è questa. Gli algoritmi utilizzati nello script fanno largo uso delle funzioni circolari math.sin e math.cos, e potrebbe risiedere qui il motivo del rallentamento.
Ciò che chiedo è sapere se Python possiede uno o più pacchetti di elaborazione matematica che ne riducano drasticamente i tempi di esecuzione dello script, che ho postato sotto insieme al rispettivo di MatLab.
Grazie anticipate e Buona Pasqua
Re: [Python/MatLab] Test di velocità
Inviato: sabato 15 aprile 2017, 9:18
da Claudio_F
Hai messo un tar dentro a un altro tar e il mio Ubuntu mi dice formato non supportato...
Navigando alla cieca: Python è lento quando si scrive un algoritmo interamente Python, non lo è se si sfruttando a fondo le librerie C compilate.
In particolare ci sono alcuni accorgimenti più o meno comuni che si riassumono sempre in "evitare di ripetere le operazioni", il che può essere più o meno fattibile a seconda del contesto.
Comuni ad ogni linguaggio:
- evitare di ripetere calcoli (usando variabili appoggio temporanee)
- evitare le chiamate a funzione
- srotolare i loop brevi
Specifiche Py:
- evitare la continua risoluzione dei nomi (usando variabili appoggio temporanee per contenere il riferimento finale all'oggetto che ci interessa)
- usare le funzioni apposite del linguaggio per gestire le sequenze (list comprehension piuttosto di for, appartenenza piuttosto che test espliciti ecc, non ho mai provato la selezione tramite dict vs confronti relazionali)
Nota1: qualche volta si ottengono risultati controintuitivi, misurare cosa per Py è più veloce.
Nota2: Py3 è più lento di Py2
Re: [Python/MatLab] Test di velocità
Inviato: sabato 15 aprile 2017, 9:20
da TommyB1992
Conoscere le tecniche di ottimizzazione in Python è fondamentale per applicazioni che richiedono alte prestazioni in quanto non è progettato.
E' possibile trovare online applicazioni ottimizzate in Python sviluppate apposta per dimostrare di essere più veloci delle controparti C/C++.
Questo ti può aiutare
Re: [Python/MatLab] Test di velocità
Inviato: sabato 15 aprile 2017, 10:07
da BlueEyes
Claudio_F ha scritto:
Hai messo un tar dentro a un altro tar e il mio Ubuntu mi dice formato non supportato...
Ho verificato, ed ottengo quanto mostra la figura. Non so che dirti, ma è importante che qualcuno replichi i miei due test Python/MatLab. Grazie, comunque
Re: [Python/MatLab] Test di velocità
Inviato: domenica 16 aprile 2017, 0:35
da crap0101
il confronto python/matlab non posso farlo, a naso mi sembra normale che codice non particolarmente ottimizzato gira più veloce utilizzando uno strumento (matlab) specifico per certi compiti piuttosto che con uno strumento generico (python) a meno che non si usino moduli specifici.
La differenza è notevole, per capire bene il perchè bisognerebbe conoscere bene entrambi i linguaggi... quello che posso ipotizzare è che matlab faccia per te il lavoro che ho fatto io qua sotto

ottimizzando il codice evitando di ripetere calcoli inutilmente. Sul perchè python non fa lo stesso... è una discussione che rischia di diventare lunga (e forse si era anche già fatta) e magari anche OT, btw ci sono una serie di motivi.
ho messo alcune parti modificate tra
tranne i print che ho modificato nel più "ovvio" stringa.format
Codice: Seleziona tutto
# -------- t1.py ---------- brute force test (15.Apr.17)
import math
rad = math.pi / 180 # radian factor
#'--------------------------
#'Dati in centimetri
a = 10.0
b = 8.9
w = 1.0
tol = 1e-5 # tolleranza
#---------------------------
# Costanti
Mo = 126e-8
cost = Mo / (4 * math.pi)
#'--------------------------
M3 = 960 # intervalli
M4 = 6 # intervalli
#---------------------------
a = a / 100
b = b / 100
w = w / 100
#------------------
ecc = math.sqrt(1 - (b / a) ** 2)
#
Sommaintegra1 = 0.0
Integra1 = 0.0
#
alfa1 = 0.0
alfa2 = 2 * math.pi
beta1 = 0.0
beta2 = 2 * math.pi
larg1 = 0.0
lorg1 = 0.0
incalfa = (alfa2 - alfa1) / M3
incbeta = (beta2 - beta1) / M3
Integra1 = 0.0
Sommaintegra1 = 0.0
inclarg = (w - larg1) / M4
inclorg = (w - lorg1) / M4
#+!!!
_sqrt = math.sqrt
_sin = math.sin
_cos = math.cos
ecc_pow = ecc ** 2
inc_a_b = incalfa*incbeta
inc_a_b_larg = inc_a_b*inclarg
inc_abl_lo = inc_a_b_larg*inclorg
#-!!!
#' ------ 4 Cicli nidificati ----------
for la in range (0,M3+1):
alfa = alfa1 + la * incalfa
#+!!!
sin_alfa = _sin(alfa)
cos_alfa = _cos(alfa)
#-!!!
N1 = a / _sqrt(1 - ecc_pow * sin_alfa ** 2)
#+!!!
n1_ecc_sin_a = N1*(1-ecc_pow)*sin_alfa
n1_cos_a = N1*cos_alfa
#-!!!
print(' la= {:03d}'.format(la))
for lo in range (0,M4):
larg = larg1 + lo * inclarg
for al in range (0,M3+1):
beta = beta1 + al * incbeta
#+!!!
sin_beta = _sin(beta)
#-!!!
N2 = a / _sqrt(1 - ecc_pow * sin_beta ** 2)
#+!!!
powredux = (n1_cos_a - N2*_cos(beta))**2 + (n1_ecc_sin_a - N2*(1-ecc_pow)*sin_beta)**2
fooredux = _cos(beta - alfa)*N1*N2 * inc_abl_lo
#-!!!
for be in range (0,M4):
lorg = lorg1 + be * inclorg
den1= _sqrt(powredux + (larg-lorg)**2)
if den1 > tol:
Integra1 += fooredux/den1
#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sommaintegra1 += Integra1
Lsett = (cost * Sommaintegra1) / (w ** 2)
#
print("\n\tL= {:.4e}".format(Lsett))
# ------- EOF: t1.py ------
Nota come i tempi si riducono di un terzo
Codice: Seleziona tutto
crap0101@orange:/tmp/foo$ time python3 t.py > out_t # codice tuo allegato
real 2m32.667s
user 2m32.616s
sys 0m0.012s
crap0101@orange:/tmp/foo$ time python3 t1.py > out_t1 # codice leggermente modificato, giusto qualche alias per i moduli
real 2m22.057s
user 2m21.728s
sys 0m0.288s
crap0101@orange:/tmp/foo$ diff -s out_t out_t1
I file out_t e out_t1 sono identici
crap0101@orange:/tmp/foo$ time python3 t1.py > out_t2 # codice modificato (quello postato) con rimozione dei calcoli inutili
real 0m49.664s
user 0m49.456s
sys 0m0.032s
crap0101@orange:/tmp/foo$ diff -s out_t out_t2
I file out_t e out_t2 sono identici
Re: [Python/MatLab] Test di velocità
Inviato: domenica 16 aprile 2017, 7:27
da BlueEyes
Ottimo suggerimento,
crap!
Alla manipolazione degli algoritmi _non_ ci avevo proprio pensato:
Codice: Seleziona tutto
#+!!!
_sqrt = math.sqrt
_sin = math.sin
_cos = math.cos
ecc_pow = ecc ** 2
inc_a_b = incalfa*incbeta
inc_a_b_larg = inc_a_b*inclarg
inc_abl_lo = inc_a_b_larg*inclorg
#-!!!
E questa è importantissima per il mio esempio di 'brute force', dove le funzioni matematiche/goniometriche sono largamente diffuse in ognuno di quei milioni di cicli della procedura.
Sì, confermo, adesso i tempi di esecuzione sono passati da 102 a 35s, e
questo mi può bastare. Nel senso che la mia idiosincrasia con MatLab ha radici lontane: i) perché tale diffusissimo pacchetto informatico è chiuso e protetto da licenza [il suo clone Octave, opensourced, nei casi come questo è un palliativo, tempi di esecuzione da era glaciale]; ii) perché si è obbligati a passare da una 'miriade' di shell nelle due fasi fondamentali di editing e avvio. Ecco perché sto cercando di convertire alcuni miei script .m in un linguaggio snello e scattante come Python, e l'aiuto di un forum come il nostro è quello che serve.
Grazie mille, crap, e alla prossima.
Edit. Ecco il file corretto, con l'aggiunta del tempo impiegato
Codice: Seleziona tutto
.........
la= 957
la= 958
la= 959
la= 960
L= 5.5414e-07
Tempo di esecuzione= 33.141 secondi
Edit2. A completamento della discussione trascrivo sotto i tempi di esecuzione di MatLab e del suo clone Octave: 7 secondi vs. 24min 07s, che scarto!
Codice: Seleziona tutto
1.. MatLab 8.0
.....
la= 957
la= 958
la= 959
la= 960
L= 5.5293e-07
Elapsed time is 6.897877 seconds. <<<<<<----------
2.. Octave (vers. opensource di MatLab)
..........
la= 957
la= 958
la= 959
la= 960
L= 5.5293e-007
Elapsed time is 1447.3 seconds. <<<<<<----------