[Corso Python3] Fwd: Velocità esecuzione blocchi if, try
Gianluca Biondi
gluca.biondi a gmail.com
Sab 11 Giu 2016 18:04:04 CEST
Il 24 maggio 2016 13:03, Gianluca Biondi <gluca.biondi a gmail.com> ha scritto:
> Buonasera a tutti!!
>
> Istruzioni:
>
> creare un ambiente virtuale (prima lezione -> virtualenv --python=python3 env
> env (env è la cartella in cui si sta installando)
> source bin/activate (attiva l'ambiente virtuale)
> pip install pygal (serve a generare i grafici)
> copiare nella cartella virtuale il file allegato (test_execution_speed_class.py)
> dare il comando python test_execution_speed_class.py
> nella cartella dove avete messo il file verrà creata una cartella con il
> nome 'grafici'
> apriteli con un browser (al visualizzatore di immagini di debian non
> piacciono tanto)
>
Come mi è stato fatto notare sabato, c'era qualcosa che non andava
(in pratica avevo dimostrato solo che le istruzioni ci mettono sempre
lo stesso tempo ad eseguire.... :( )
Ho fatto alcune modifiche (che trovate elencate ad inizio script),
e ho aggiunto altre funzioni.
Enjoy,
Gluca
A quanto pare gli allegati non passano per la mailing list...
# ###################################################
"""
Genera delle liste di dati casuali con alcune eccezioni all'interno
(stringhe vuote) e fa dei calcoli sui valori allo scopo di scoprire
se sia più efficiente usare un blocco if, else un blocco Try, except
o una list comprehension, etc... per filtrare le eccezioni.
#
I dati vanno raggruppati per probabilità, che va testata da 0 a 1.
Modifico il metodo "prova_tempi" per passare due liste invece che 6 parametri.
Aggiunto controllo parametri in "prova_tempi".
Aggiunto metodo per stampare i grafici per numero di campioni.
Corretto sul grafico la stampa della prob, non più da 0 a 1000 ma da 0 a 1
"""
# Mettiamo i grafici in una cartella
from os import makedirs
# Mi serve per dividere gli elementi quando genero il grafico
from collections import Counter
from random import randint
from time import time
# Un grafico 3D non è così semplice da realizzare. Mi accontento del 2D
import pygal
from pygal.style import LightSolarizedStyle
class Test_execution_speed():
def __init__(self):
pass
def _lista_dati_casuali(self, num_valori, probabilita):
"""
Crea un array di num_valori, con 'probabilità'su 1000 di possibilità di
avere una lista vuota al suo interno. Ritorna la lista.
"""
lista_valori = []
for i in range(num_valori):
numero_random = randint(1, 1000)
if numero_random <= probabilita: # < -> <=, prob=1->tutti i val
lista_valori.append('')
else:
lista_valori.append(numero_random)
return lista_valori # tuple(lista_valori)
def _test_con_if(self, lista):
"""
Scansiona i dati della lista e, se c'è un numero esegue una divisione.
l'eccezzione è gestita da if, else.
Ritorna il numero delle volte che non effettua operazioni
"""
num_errori = 0
for elemento in lista:
if type(elemento) == type(1):
1 / elemento
else:
num_errori += 1
return num_errori
def _test_con_if_is(self, lista):
"""
Scansiona i dati della lista e, se c'è un numero esegue una divisione.
l'eccezzione è gestita da if, else.
Ritorna il numero delle volte che non effettua operazioni
Al posto di ==, is
"""
num_errori = 0
for elemento in lista:
if type(elemento) is type(1):
1 / elemento
else:
num_errori += 1
return num_errori
def _test_con_if_isinstance(self, lista):
"""
Scansiona i dati della lista e, se c'è un numero esegue una divisione.
l'eccezzione è gestita da if, else ed il controllo da isinstance.
Ritorna il numero delle volte che non effettua operazioni.
Al posto di usare type()==type() uso la funzione isinstance().
"""
num_errori = 0
for elemento in lista:
if isinstance(elemento, int):
1 / elemento
else:
num_errori += 1
return num_errori
def _test_con_try(self, lista):
"""
Scansiona i dati della lista e, se c'è un numero esegue una divisione.
l'eccezzione è gestita da try ed except.
Ritorna il numero delle volte che non effettua operazioni
"""
num_errori = 0
for elemento in lista:
try:
1 / elemento
except:
num_errori += 1
return num_errori
def _test_con_lC(self, lista):
"""
Crea una nuova lista con i valori della list comprehension.
Ritorna il numero delle volte che non effettua operazioni
"""
num_errori = (len(lista) -
len([1/i for i in lista if type(i) == type(1)]))
return num_errori
def _test_con_lC_meno_type(self, lista):
"""
Crea una nuova lista con i valori della list comprehension.
Ritorna il numero delle volte che non effettua operazioni
Ho tolto una chiamata a type().
"""
ctr = type(1)
num_errori = len(lista) - len([1/i for i in lista if type(i) == ctr])
return num_errori
def _test_con_lC_meno_type_is(self, lista):
"""
Crea una nuova lista con i valori della list comprehension.
Ritorna il numero delle volte che non effettua operazioni.
Ho tolto una chiamata a type() e al posto di ==, is.
"""
ctr = type(1)
num_errori = len(lista) - len([1/i for i in lista if type(i) is ctr])
return num_errori
def _test_con_FG_meno_type_is(self, lista):
"""
Crea una nuova lista con i valori della Function Generator.
Ritorna il numero delle volte che non effettua operazioni.
Ho tolto una chiamata a type() e al posto di ==, is.
"""
ctr = type(1)
num_errori = (len(lista) -
len(list((1/i for i in lista if type(i) is ctr))))
return num_errori
def prova_tempi(self, lista_valori_da_testare, lista_prob_da_testare):
"""
Cicla tra i valori di num_valori e probabilità e segna i tempi di
elaborazione. Ritorna una lista di tuple contenente i risultati
ordinati come:
Nome Funzione, Prob, Nr_valori, Nr_errori, tempo_exec
"""
# Controllo se i dati in ingresso sono liste e > 0
if ((not isinstance(lista_valori_da_testare, list)) or
(len(lista_valori_da_testare) <= 0)):
print('La lista dei valori da testare non è corretta!!')
raise SystemExit # Problema?Esco dal programma!
if ((not isinstance(lista_prob_da_testare, list)) or
(len(lista_prob_da_testare) <= 0)):
print('La lista delle probabilità non è corretta!!')
raise SystemExit # Problema?Esco dal programma!
# Lista dei risultati e coordinate
risultati = []
# Funzioni da chiamare: aggiungere una 'chiave: valore'
# con valore = nome funzione per aggiungere altri test
func_to_call = {'if': self._test_con_if,
'if is': self._test_con_if_is,
'if_istance': self._test_con_if_isinstance,
'try': self._test_con_try,
'lc': self._test_con_lC,
'lc - type': self._test_con_lC_meno_type,
'lc,-type,is': self._test_con_lC_meno_type_is,
'Func Gener': self._test_con_FG_meno_type_is}
# Ciclo tra i valori di prob, di quantità e cronometro l'esecuzione
for prob in lista_prob_da_testare:
for num_valori in lista_valori_da_testare:
lista_valori = self._lista_dati_casuali(num_valori, prob)
# Per ogni nome key, chiama la funzione associata nel dizio
for key in func_to_call:
tempo_prima = time() # cronometro start
num_errori = func_to_call[key](lista_valori)
cronometro = time() - tempo_prima # cronometro stop
# cronometro è in secondi...*1000 mi da millisecondi
# unità più ragionevole
risultati.append((str(key), prob, num_valori, num_errori,
cronometro*1000))
return risultati
def stampa_grafici_per_prob(self, lista):
"""
Crea una cartella dove salvare i grafici.
Estrae i valori dalla lista dei risultati e genera il grafico
per probabilità.
Implementare una funzione che raggruppi i dati in un altro modo
è semplice.
"""
# Crea la cartella dove mettere i grafici
# exist_ok non genera errori se esiste
makedirs('grafici', exist_ok=True)
# Configurazione del grafico
config = pygal.Config()
config.style = LightSolarizedStyle
config.show_legend = True
config.human_readable = True
config.x_title = 'Numero campioni'
config.y_title = 'Tempo ms'
# config.fill = True
# Counter mi torna una ricorrenza per elemento prob testato
prob_testate = list(Counter([ele[1] for ele in lista]))
# Lista con i nomi delle funzioni testate
indici_funzioni = list(Counter([ele[0] for ele in lista]))
for i in prob_testate:
chart = pygal.XY(config)
nome_file = ' '.join(['Grafico con probabilità =', str(i/1000)])
chart.title = nome_file
for j in indici_funzioni:
# Aggiungo al grafico (x=num_val, y=t_exec) solo se
# nome_funzione e prob_testata coincidono con j, i
chart.add(j, [(ele[2], ele[4]) for ele in lista
if (ele[0] == j and ele[1] == i)]) # Damn pep8!!
chart.render_to_file(''.join(['grafici/', nome_file, '.svg']))
# print(indici_funzioni, prob_testate, dati_if)
def stampa_grafici_per_num_valori(self, lista):
"""
Crea una cartella dove salvare i grafici.
Estrae i valori dalla lista dei risultati e genera i grafici
divisi per numero di valori testati.
Implementare una funzione che raggruppi i dati in un altro modo
è semplice.
"""
# Crea la cartella dove mettere i grafici
# exist_ok non genera errori se esiste
makedirs('grafici', exist_ok=True)
# Configurazione del grafico
config = pygal.Config()
config.style = LightSolarizedStyle
config.show_legend = True
config.human_readable = True
config.x_title = 'Valori Probabilità'
config.y_title = 'Tempo ms'
# config.fill = True
# Counter mi torna una ricorrenza per campioni testati
num_valori = list(Counter([ele[2] for ele in lista]))
# Lista con i nomi delle funzioni testate
indici_funzioni = list(Counter([ele[0] for ele in lista]))
for i in num_valori:
chart = pygal.XY(config)
nome_file = 'Test con {} campioni'.format(str(i))
chart.title = nome_file
for j in indici_funzioni:
# Aggiungo al grafico (x=prob_test, y=t_exec) solo se
# nome_funzione e campioni_testati coincidono con j, i
chart.add(j, [((ele[1]/1000), ele[4]) for ele in lista
if (ele[0] == j and ele[2] == i)]) # Damn pep8!!
chart.render_to_file(''.join(['grafici/', nome_file, '.svg']))
# print(indici_funzioni, prob_testate, dati_if)
# #############################################################################
# ## ###
# #############################################################################
tempo_prima = time()
test = Test_execution_speed()
# I dati da passare sono una lista con il numero di test da fare
# una lista con il numero di probabilità da testare
# 0 <= prob <= 1 -> prob * 1000
# le probabilità sono espresse con un numero tra 0 e 1000
# ritorna una lista di tuple
valori = test.prova_tempi([1000],
list(range(0, 1001, 100))) # <- SMANETTARE QUI
# stampo a terminale i valori generati
for i in valori:
print("".join(["Funzione: {0[0]:12s};",
"\tProbabilità: {0[1]:4d};",
"\tNumero valori: {0[2]:4d};",
"\tNumero errori: {0[3]:4d};",
"\tIn tempo: {0[4]:.6f} ms"]).format(i))
# Genero i grafici
test.stampa_grafici_per_num_valori(valori)
# test.stampa_grafici_per_prob(valori)
# Satmpa in quanto tempo ho eseguito il programma
cronometro = time() - tempo_prima
print('Ci ho messo {:6f} secondi.'.format(cronometro))
# #######################################################
Maggiori informazioni sulla lista
fsug-corso-python3