Quem nunca preciso medir o tempo de algo? Digo, em foco a programação e principalmente quando se aplica Profiling, tempo as vezes é muito importante medir. Uma coisa é fazer algo funcionar, outra coisa é com eficiência e outra é ter desempenho, muitas vezes fazemos o primeiro e esquecemos o resto, eu já quebrei a cabeça em cima de uma função tentando otimização e aplicando tudo o que eu sabia e o problema não era meu e sim de uma função de uma lib pronta. Enfim, vamos ver como podemos medir tempo de execução de programas ou trechos de códigos em python.
Em C, quem já precisou, usando a library time.h podemos criar um tipo com time_t ou clock_t e utilizando duas variáveis, chamar no inicio e no fim, no final realiza uma matemática simples, normalmente substração e temos o tempo gasto, normalmente em ms(milissegundos). E quem disse que em Python é diferente? Vamos ao código exemplo, abaixo e logo em seguida adicionar a forma de medir o tempo.
my_list_name = [ "Cleiton", "Maria", "Carlos", "Pedro", "Oscar", "Renata", "Reginaldo", "Rafael", "Tereza", "Aparecido", "Dias", "Fred", "Ronaldo", "Pamela", "Vanessa", "Ingrid", "Suellen", "Ana", "Priscila", "Willian", "Manoel", "Diego", "Henrique", "Sergio", "Cleidson", "Luiza", "Antonio", "Rafaela", "Souza", "Bueno", "Luiz", "Lucas", "Matheus", "Evandro", "Murilo", "Vinicius", "Cassio", "Bruno", "Domingues", "Miguel", "Gabriel", "Fernando", "Jane", "Luiz", "Fabio" ] my_list_sorted = sorted(my_list_name) """ Opcao 1 """ ids = 0 while ids < len(my_list_name): print("Nome: %s") % (my_list_sorted[ids]) ids+=1 """ Opcao 2 """ """ print "n".join(["Nome: %s" % x for x in my_list_sorted]) """
Minimizei ao máximo para um exemplo legal, para os testes, visto que foi tirado de um programa real a ideia do artigo, tenho uma lista com nomes my_list_name um pouco mais abaixo na linha12 eu uso sorted() para ordenar minha lista e armazenar em my_list_sorted o que quero medir aqui é entre as duas opções qual é a mais rápida, pode haver outras maneiras de tonar mais rápida ou eficiente, mas para o exemplo as duas vão apresentar resultados interessantes ;)
Primeiramente, vamos “medir” com o time do Linux.
cleiton@linuxVM:~/projetos/python/measure_time_code$ time python my_code.py Nome: Ana Nome: Antonio Nome: Aparecido Nome: Bruno Nome: Bueno Nome: Carlos Nome: Cassio Nome: Cleidson Nome: Cleiton Nome: Dias Nome: Diego Nome: Domingues Nome: Evandro Nome: Fabio Nome: Fernando Nome: Fred Nome: Gabriel Nome: Henrique Nome: Ingrid Nome: Jane Nome: Lucas Nome: Luiz Nome: Luiz Nome: Luiza Nome: Manoel Nome: Maria Nome: Matheus Nome: Miguel Nome: Murilo Nome: Oscar Nome: Pamela Nome: Pedro Nome: Priscila Nome: Rafael Nome: Rafaela Nome: Reginaldo Nome: Renata Nome: Ronaldo Nome: Sergio Nome: Souza Nome: Suellen Nome: Tereza Nome: Vanessa Nome: Vinicius Nome: Willian real 0m0.081s user 0m0.052s sys 0m0.020s
Uma breve explicação do que o Linux esta nos dizendo:
real: Tempo total ocorrido do inicio ao encerramento da aplicação
user: Tempo gasto de CPU no user-space, no modo usuario dentro do processo
sys: Tempo gasto de CPU dentro do kernel, funções e chamadas especificas do kernel
Uma referencia legal pode ser visto man do time.
OBS: Não é boa pratica dizer que real é user + sys, faça um teste com uma aplicação com multithreading e veja o resultado.
Vamos agora comentar a Opção 1 e ver o tempo da Opção 2:
my_list_name = [ "Cleiton", "Maria", "Carlos", "Pedro", "Oscar", "Renata", "Reginaldo", "Rafael", "Tereza", "Aparecido", "Dias", "Fred", "Ronaldo", "Pamela", "Vanessa", "Ingrid", "Suellen", "Ana", "Priscila", "Willian", "Manoel", "Diego", "Henrique", "Sergio", "Cleidson", "Luiza", "Antonio", "Rafaela", "Souza", "Bueno", "Luiz", "Lucas", "Matheus", "Evandro", "Murilo", "Vinicius", "Cassio", "Bruno", "Domingues", "Miguel", "Gabriel", "Fernando", "Jane", "Luiz", "Fabio" ] my_list_sorted = sorted(my_list_name) """ Opcao 1 """ """ ids = 0 while ids < len(my_list_name): print("Nome: %s") % (my_list_sorted[ids]) ids+=1 """ """ Opcao 2 """ print "n".join(["Nome: %s" % x for x in my_list_sorted])
Vamos novamente ao terminal e ver o tempo agora.
cleiton@linuxVM:~/projetos/python/measure_time_code$ time python my_code.py Nome: Ana Nome: Antonio Nome: Aparecido Nome: Bruno Nome: Bueno Nome: Carlos Nome: Cassio Nome: Cleidson Nome: Cleiton Nome: Dias Nome: Diego Nome: Domingues Nome: Evandro Nome: Fabio Nome: Fernando Nome: Fred Nome: Gabriel Nome: Henrique Nome: Ingrid Nome: Jane Nome: Lucas Nome: Luiz Nome: Luiz Nome: Luiza Nome: Manoel Nome: Maria Nome: Matheus Nome: Miguel Nome: Murilo Nome: Oscar Nome: Pamela Nome: Pedro Nome: Priscila Nome: Rafael Nome: Rafaela Nome: Reginaldo Nome: Renata Nome: Ronaldo Nome: Sergio Nome: Souza Nome: Suellen Nome: Tereza Nome: Vanessa Nome: Vinicius Nome: Willian real 0m0.078s user 0m0.056s sys 0m0.016s
Ok, analisando nossa segunda opção, pareceu que se saiu melhor, mas nossa aplicação é pequena, e se antes disso executasse outras funções e queremos por exemplo, ver o que é mais rápido a Opção 1 ou a Opção 2, vamos ver agora o Time, modifique o nosso código conforme abaixo.
import time my_list_name = [ "Cleiton", "Maria", "Carlos", "Pedro", "Oscar", "Renata", "Reginaldo", "Rafael", "Tereza", "Aparecido", "Dias", "Fred", "Ronaldo", "Pamela", "Vanessa", "Ingrid", "Suellen", "Ana", "Priscila", "Willian", "Manoel", "Diego", "Henrique", "Sergio", "Cleidson", "Luiza", "Antonio", "Rafaela", "Souza", "Bueno", "Luiz", "Lucas", "Matheus", "Evandro", "Murilo", "Vinicius", "Cassio", "Bruno", "Domingues", "Miguel", "Gabriel", "Fernando", "Jane", "Luiz", "Fabio" ] my_list_sorted = sorted(my_list_name) """ Opcao 1 """ inicio=time.time() ids = 0 while ids < len(my_list_name): print("Nome: %s") % (my_list_sorted[ids]) ids+=1 fim=time.time() print("nTempo total Op.1: %f") % (fim-inicio) print """ Opcao 2 """ inicio=time.time() print "n".join(["Nome: %s" % x for x in my_list_sorted]) fim=time.time() print("nTempo total Op.2: %f") % (fim-inicio) print
Hum, legal! Agora vou medir antes de entrar de executar a Opção 1 e parar quando sair e o mesmo na Opção 2 e imprimir na tela o tempo, vamos ver.
cleiton@linuxVM:~/projetos/python/measure_time_code$ time python my_code.py Nome: Ana Nome: Antonio Nome: Aparecido Nome: Bruno Nome: Bueno Nome: Carlos Nome: Cassio Nome: Cleidson Nome: Cleiton Nome: Dias Nome: Diego Nome: Domingues Nome: Evandro Nome: Fabio Nome: Fernando Nome: Fred Nome: Gabriel Nome: Henrique Nome: Ingrid Nome: Jane Nome: Lucas Nome: Luiz Nome: Luiz Nome: Luiza Nome: Manoel Nome: Maria Nome: Matheus Nome: Miguel Nome: Murilo Nome: Oscar Nome: Pamela Nome: Pedro Nome: Priscila Nome: Rafael Nome: Rafaela Nome: Reginaldo Nome: Renata Nome: Ronaldo Nome: Sergio Nome: Souza Nome: Suellen Nome: Tereza Nome: Vanessa Nome: Vinicius Nome: Willian Tempo total Op.1: 0.011110 Nome: Ana Nome: Antonio Nome: Aparecido Nome: Bruno Nome: Bueno Nome: Carlos Nome: Cassio Nome: Cleidson Nome: Cleiton Nome: Dias Nome: Diego Nome: Domingues Nome: Evandro Nome: Fabio Nome: Fernando Nome: Fred Nome: Gabriel Nome: Henrique Nome: Ingrid Nome: Jane Nome: Lucas Nome: Luiz Nome: Luiz Nome: Luiza Nome: Manoel Nome: Maria Nome: Matheus Nome: Miguel Nome: Murilo Nome: Oscar Nome: Pamela Nome: Pedro Nome: Priscila Nome: Rafael Nome: Rafaela Nome: Reginaldo Nome: Renata Nome: Ronaldo Nome: Sergio Nome: Souza Nome: Suellen Nome: Tereza Nome: Vanessa Nome: Vinicius Nome: Willian Tempo total Op.2: 0.000851
Nossa! Neste caso List Comprehensions mandou muito bem heim.
Maravilha, vimos como medir o tempo de execução de um trecho de código no Python, pode estender fácil para funções e afins, mas descobri algo muito interessante neste aspecto no Python, quando passeando encontrei no Debugging and Profiling o Timeit.
A função timeit.timeit() e timeit.repeat(), segundo a documentação segue sua estrutura:
timeit.timeit(stmt=’pass’, setup=’pass’, timer=, number=1000000)
timeit.repeat(stmt=’pass’, setup=’pass’, timer=, repeat=3, number=1000000)
Os parâmetros importantes e bom saber são:
Statement ou stmt: A função que sera “testada”
setup: O código básico para iniciar e realizar os testes
number: Numero de loops a realizar com a função, valor padrão é 1000000
repeat: Quantas baterias de number serão feitas (valido somente no timeit.repeat()
Vamos agora, passar nossos dois códigos em duas funções opcao1() e opcao2() e implementar os testes com timeit.
import timeit my_list_name = [e "Cleiton", "Maria", "Carlos", "Pedro", "Oscar", "Renata", "Reginaldo", "Rafael", "Tereza", "Aparecido", "Dias", "Fred", "Ronaldo", "Pamela", "Vanessa", "Ingrid", "Suellen", "Ana", "Priscila", "Willian", "Manoel", "Diego", "Henrique", "Sergio", "Cleidson", "Luiza", "Antonio", "Rafaela", "Souza", "Bueno", "Luiz", "Lucas", "Matheus", "Evandro", "Murilo", "Vinicius", "Cassio", "Bruno", "Domingues", "Miguel", "Gabriel", "Fernando", "Jane", "Luiz", "Fabio" ] my_list_sorted = sorted(my_list_name) def opcao1(): ids = 0 while ids < len(my_list_name): print("Nome: %s") % (my_list_sorted[ids]) ids+=1 def opcao2(): print "n".join(["Nome: %s" % x for x in my_list_sorted]) tempo_op1 = timeit.timeit("opcao1()", "from __main__ import opcao1", number=10) tempo_op2 = timeit.timeit("opcao2()", "from __main__ import opcao2", number=10) print("Opcao1 com 10 = %f") % (tempo_op1) print("Opcao2 com 10 = %f") % (tempo_op2)
Importamos o timeit, colocamos em duas funções o que queremos “testar” e inserimos duas variaveis tempo_op1 e tempo_op2 que recebem timeit.timeit(), a estrutura é primeiro a função, segundo setup basico para inicializar e utilizar a função e no caso, coloquei numero de 10 loops, visto que 1.000.000 com esses prints seria um pouco exaustivo não?
Vamos ver a saída.
cleiton@linuxVM:~/projetos/python/otimizacao$ python my_code_def_final.py Nome: Ana Nome: Antonio Nome: Aparecido Nome: Bruno Nome: Bueno Nome: Carlos Nome: Cassio Nome: Cleidson Nome: Cleiton ... Nome: Vanessa Nome: Vinicius Nome: Willian Opcao1 com 10 = 0.057217 Opcao2 com 10 = 0.000649
Hum, agora vamos fazer com 10, 100 e 1000 loops:
import timeit my_list_name = [ "Cleiton", "Maria", "Carlos", "Pedro", "Oscar", "Renata", "Reginaldo", "Rafael", "Tereza", "Aparecido", "Dias", "Fred", "Ronaldo", "Pamela", "Vanessa", "Ingrid", "Suellen", "Ana", "Priscila", "Willian", "Manoel", "Diego", "Henrique", "Sergio", "Cleidson", "Luiza", "Antonio", "Rafaela", "Souza", "Bueno", "Luiz", "Lucas", "Matheus", "Evandro", "Murilo", "Vinicius", "Cassio", "Bruno", "Domingues", "Miguel", "Gabriel", "Fernando", "Jane", "Luiz", "Fabio" ] my_list_sorted = sorted(my_list_name) def opcao1(): ids = 0 while ids < len(my_list_name): print("Nome: %s") % (my_list_sorted[ids]) ids+=1 def opcao2(): print "n".join(["Nome: %s" % x for x in my_list_sorted]) """ Primeira Bateria """ tempo_op1 = timeit.timeit("opcao1()", "from __main__ import opcao1", number=10) tempo_op2 = timeit.timeit("opcao2()", "from __main__ import opcao2", number=10) """ Segunda Bateria """ tempo_op11 = timeit.timeit("opcao1()", "from __main__ import opcao1", number=100) tempo_op21 = timeit.timeit("opcao2()", "from __main__ import opcao2", number=100) """ Terceira Bateria """ tempo_op12 = timeit.timeit("opcao1()", "from __main__ import opcao1", number=1000) tempo_op22 = timeit.timeit("opcao2()", "from __main__ import opcao2", number=1000) print("Opcao1 com 10 = %f") % (tempo_op1) print("Opcao2 com 10 = %f") % (tempo_op2) print print("Opcao1 com 100 = %f") % (tempo_op11) print("Opcao2 com 100 = %f") % (tempo_op21) print print("Opcao1 com 1000 = %f") % (tempo_op12) print("Opcao2 com 1000 = %f") % (tempo_op22)
Vamos ver a saída:
cleiton@linuxVM:~/projetos/python/otimizacao$ python my_code_def_final.py Nome: Ana Nome: Antonio Nome: Aparecido Nome: Bruno Nome: Bueno Nome: Carlos Nome: Cassio Nome: Cleidson Nome: Cleiton ... Nome: Renata Nome: Ronaldo Nome: Sergio Nome: Souza Nome: Suellen Nome: Tereza Nome: Vanessa Nome: Vinicius Nome: Willian Opcao1 com 10 = 0.046940 Opcao2 com 10 = 0.002445 Opcao1 com 100 = 0.248750 Opcao2 com 100 = 0.217057 Opcao1 com 1000 = 2.481773 Opcao2 com 1000 = 1.960809
Para encerrar, agora uma amostra usando time.repeat().
import timeit my_list_name = [ "Cleiton", "Maria", "Carlos", "Pedro", "Oscar", "Renata", "Reginaldo", "Rafael", "Tereza", "Aparecido", "Dias", "Fred", "Ronaldo", "Pamela", "Vanessa", "Ingrid", "Suellen", "Ana", "Priscila", "Willian", "Manoel", "Diego", "Henrique", "Sergio", "Cleidson", "Luiza", "Antonio", "Rafaela", "Souza", "Bueno", "Luiz", "Lucas", "Matheus", "Evandro", "Murilo", "Vinicius", "Cassio", "Bruno", "Domingues", "Miguel", "Gabriel", "Fernando", "Jane", "Luiz", "Fabio" ] my_list_sorted = sorted(my_list_name) def opcao1(): ids = 0 while ids < len(my_list_name): print("Nome: %s") % (my_list_sorted[ids]) ids+=1 def opcao2(): print "n".join(["Nome: %s" % x for x in my_list_sorted]) tempo_op1 = timeit.repeat("opcao1()", "from __main__ import opcao1", repeat=5, number=10) tempo_op2 = timeit.repeat("opcao2()", "from __main__ import opcao2", repeat=5, number=10) print("Opcao1 com repeat 5 = %s") % tempo_op1 print("Opcao2 com repeat 5 = %s") % tempo_op2
Vamos fazer 10 loops com 5 baterias, vamos ver a saída:
cleiton@linuxVM:~/projetos/python/otimizacao$ python my_code_def_final.py Nome: Ana Nome: Antonio Nome: Aparecido Nome: Bruno Nome: Bueno Nome: Carlos Nome: Cassio Nome: Cleidson Nome: Cleiton ... Nome: Suellen Nome: Tereza Nome: Vanessa Nome: Vinicius Nome: Willian Opcao1 com repeat 5 = [0.04651808738708496, 0.031491994857788086, 0.032666921615600586, 0.016332149505615234, 0.05835700035095215] Opcao2 com repeat 5 = [0.00022292137145996094, 0.0015659332275390625, 0.0009109973907470703, 0.001811981201171875, 0.001252889633178711]
Ele nos devolve uma lista com o tempo de cada bateria.
Gostaram? Viu que Python não é só uma linguagem fácil e excelente para prototipar, quanto mais você mergulha mais ela se torna poderosa e mostra recursos. Isso porque os testes foram focado em uma ideia fixa, não abordei cProfile, profile, trace, pstats, hotshot, line_profiler, memory_profiler, pypy, psyco da pra ver que tem bastante coisa pra falar ainda né?
Espero que tenham gostado e até a próxima!
Referências
http://man7.org/linux/man-pages/man1/time.1.html
https://docs.python.org/2/library/timeit.html
https://docs.python.org/2/library/time.html
https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions
https://docs.python.org/2/library/debug.html
Medindo tempo de execução de código Python
Python – Medindo tempo de execução by Cleiton Bueno is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.