[Risolto] [Python/MatLab] Test di velocità

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Avatar utente
BlueEyes
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1330
Iscrizione: giovedì 15 marzo 2012, 14:08

[Risolto] [Python/MatLab] Test di velocità

Messaggio 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
Allegati
due-file.tar.gz
(1.22 KiB) Scaricato 25 volte
Ultima modifica di BlueEyes il domenica 16 aprile 2017, 7:27, modificato 1 volta in totale.
Avatar utente
Claudio_F
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1463
Iscrizione: lunedì 28 maggio 2012, 18:49
Desktop: Mate/Gnome
Distribuzione: Ubu22.04

Re: [Python/MatLab] Test di velocità

Messaggio 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
TommyB1992
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 862
Iscrizione: domenica 7 luglio 2013, 15:55
Desktop: GNU/Linux
Distribuzione: Ubuntu 22.04.2 LTS
Sesso: Maschile

Re: [Python/MatLab] Test di velocità

Messaggio 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
Avatar utente
BlueEyes
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1330
Iscrizione: giovedì 15 marzo 2012, 14:08

Re: [Python/MatLab] Test di velocità

Messaggio da BlueEyes »

00.PNG
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
Avatar utente
crap0101
Rampante Reduce
Rampante Reduce
Messaggi: 8242
Iscrizione: martedì 30 ottobre 2007, 6:33
Desktop: LXDE
Distribuzione: Ubuntu 18.04.1 LTS
Sesso: Maschile
Località: TO
Contatti:

Re: [Python/MatLab] Test di velocità

Messaggio 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 :-D 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

Codice: Seleziona tutto

#+!!!
...
#-!!!
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
http://www.gnu.org/ http://boinc.berkeley.edu/ http://www.python-it.org/
- Ricorda le ultime parole di suo padre: «Sta' alla larga dalle chiese, figlio. La sola cosa per cui hanno la chiave è il merdaio. E giurami che non porterai mai un distintivo della legge» - W.S. Burroughs
Avatar utente
BlueEyes
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1330
Iscrizione: giovedì 15 marzo 2012, 14:08

Re: [Python/MatLab] Test di velocità

Messaggio 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!
Spoiler
Mostra

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.           <<<<<<----------
Allegati
file-finale.tar.gz
(1.01 KiB) Scaricato 25 volte
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 3 ospiti