Performance Python: Como construir métodos e funções fast and furious?

Performance Python: Como construir métodos e funções fast and furious?

Já fez uma função/método que travou sua máquina ao ser executada!? Pois é ... Eu já!

Nesta palestra demonstrarei:
- Alternativas para que você não trave nada na sua máquina por falta de memória ou cpu;
- Como você poderá distinguir uma função Fuscão preto de uma função Brasília amarela.

Transcript

  1. 2.

    Eu Rafael Henrique da Silva Correia @rafaelhenrique http://blog.abraseucodigo.com.br - Desenvolvedor

    Python na Olist (temos vagas!) - Aprendiz de Golang - Rogue em World of Warcraft - Não gosto de Java!
  2. 3.

    Performance? Gastar menos e fazer mais! • Menos uso de

    CPU e conseguir terminar suas tarefas • Menos uso de memória RAM e conseguir terminar suas tarefas • Menos uso de I/O de disco e conseguir terminar suas tarefas Ou seja, o mais importante é terminar suas tarefas em um tempo aceitável! :-)
  3. 4.

    Que comece a corrida... ## Qual código é mais veloz

    (e furioso)? # Primeiro exemplo grupys_infinitos = [] for edicao in range(0,10000): grupys_infinitos.append(f'Grupy-SP {edicao}') # Segundo exemplo grupys_infinitos = [f'Grupy-SP {edicao}' for edicao in range(0,10000)]
  4. 6.

    Use o timeit! [1] >>> import timeit >>> meu_codigo_1 =

    """ grupys_infinitos = [] for edicao in range(0,10000): grupys_infinitos.append(f'Grupy-SP {edicao}') """ >>> timeit.timeit(meu_codigo_1, number=10000) 20.100100330018904 Ref. https://docs.python.org/3/library/timeit.html
  5. 7.

    Use o timeit! [2] >>> import timeit >>> meu_codigo_2 =

    """ grupys_infinitos = [f'Grupy-SP {edicao}' for edicao in range(0,10000)] """ >>> timeit.timeit(meu_codigo_2, number=10000) 13.710857237980235 >>> # Este é mais veloz (e furioso!) Ref. https://docs.python.org/3/library/timeit.html
  6. 8.

    Use o timeit! [3] $ python3 -m timeit '"-".join(str(n) for

    n in range(100))' 10000 loops, best of 5: 30.2 usec per loop $ python3 -m timeit '"-".join([str(n) for n in range(100)])' 10000 loops, best of 5: 27.5 usec per loop $ python3 -m timeit '"-".join(map(str, range(100)))' 10000 loops, best of 5: 23.2 usec per loop Ref. https://docs.python.org/3/library/timeit.html
  7. 9.

    Criamos um código Dominic Toretto? Para este problema sim! :-)

    Motivos: • O código é veloz? … Sim é! • Consigo completar sua execução? … Sim consigo! • O tempo de processamento é muito alto? … Não é! • O consumo de memória é muito alto? … Presumo que não :-/
  8. 11.

    Como medir o consumo de memória? [1] Ref. https://stackoverflow.com/questions/14372006/variables-memory-size-in-python #

    O que consome mais uma tupla ou uma lista? >>> from sys import getsizeof >>> tupla = tuple(f'Grupy-SP {edicao}' for edicao in range(0,10000)) >>> getsizeof(tupla) 80048 >>> lista = list(f'Grupy-SP {edicao}' for edicao in range(0,10000)) >>> getsizeof(lista) 83112
  9. 12.

    Como medir o consumo de memória? [2] pip install memory_profiler

    Ref. https://pypi.org/project/memory_profiler/
  10. 13.

    Como medir o consumo de memória? [2] from memory_profiler import

    profile @profile def multiplica_letra(): a = 'a' * 10000000 b = 'b' * 10000001 del b return a if __name__ == '__main__': multiplica_letra() Ref. https://pypi.org/project/memory_profiler/
  11. 14.

    Como medir o consumo de memória? [2] Filename: teste05.py Line

    # Mem usage Increment Line Contents ================================================ 3 13.2 MiB 13.2 MiB @profile 4 def multiplica_letra(): 5 22.8 MiB 9.5 MiB a = 'a' * 10000000 6 32.1 MiB 9.3 MiB b = 'b' * 10000001 7 22.8 MiB -9.3 MiB del b 8 22.8 MiB 0.0 MiB return a Ref. https://pypi.org/project/memory_profiler/
  12. 15.

    Como medir o consumo de memória? [3] from memory_profiler import

    profile @profile def grupys_infinitos_01(): grupys_infinitos = [] for edicao in range(0, 10000): grupys_infinitos.append(f'Grupy-SP {edicao}') return grupys_infinitos if __name__ == '__main__': grupys_infinitos_01() Ref. https://pypi.org/project/memory_profiler/
  13. 16.

    Como medir o consumo de memória? [3] Filename: teste06.py Line

    # Mem usage Increment Line Contents ================================================ 4 13.3 MiB 13.3 MiB @profile 5 def grupys_infinitos_01(): 6 13.3 MiB 0.0 MiB grupys_infinitos = [] 7 13.9 MiB 0.7 MiB for edicao in range(0, 10000): 8 13.9 MiB 0.0 MiB grupys_infinitos.append... 9 13.9 MiB 0.0 MiB return grupys_infinitos Ref. https://pypi.org/project/memory_profiler/
  14. 17.

    Como medir o consumo de memória? [4] from memory_profiler import

    profile @profile def grupys_infinitos_02(): return [f'Grupy-SP {edicao}' for edicao in range(0, 10000)] if __name__ == '__main__': grupys_infinitos_02() Ref. https://pypi.org/project/memory_profiler/
  15. 18.

    Como medir o consumo de memória? [4] Filename: teste07.py Line

    # Mem usage Increment Line Contents ================================================ 12 13.1 MiB 13.1 MiB @profile 13 def grupys_infinitos_02(): 14 13.8 MiB 0.7 MiB return [f'Grupy-SP {edicao}' ... Ref. https://pypi.org/project/memory_profiler/
  16. 20.

    Como medir o consumo de CPU? [1] Ref. https://docs.python.org/3/library/profile.html import

    cProfile import io import pstats pr = cProfile.Profile() pr.enable() [your code here] pr.disable() stream = io.StringIO() ps = pstats.Stats(pr, stream=stream).sort_stats('cumulative') ps.print_stats(10) print(stream.getvalue())
  17. 21.

    Como medir o consumo de CPU? [1] [your code begin...]

    import time def brasilia(): time.sleep(10) def fusca(): time.sleep(9) brasilia() fusca() [your code end...] Ref. https://docs.python.org/3/library/profile.html
  18. 22.

    Como medir o consumo de CPU? [1] 5 function calls

    in 19.005 seconds Ordered by: cumulative time ncalls tottime percall cumtime percall filename:lineno(function) 2 19.005 9.503 19.005 9.503 {built-in method time.sleep} 1 0.000 0.000 10.005 10.005 teste08.py:6(brasilia) 1 0.000 0.000 9.001 9.001 teste08.py:10(fusca) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} Ref. https://docs.python.org/3/library/profile.html
  19. 24.

    Como medir o consumo de CPU? [2] pip install pytest-benchmark

    Ref. https://pypi.org/project/pytest-benchmark/
  20. 25.

    Como medir o consumo de CPU? [2] def soma(x, y):

    return x + y def teste_soma(benchmark): # realiza benchmark da função de soma result = benchmark(soma, 10, 20) # verifica se a soma deu o resultado esperado assert result == 30 Ref. https://pypi.org/project/pytest-benchmark/
  21. 26.

    Como medir o consumo de CPU? [2] $ # Executando

    o código $ pytest --benchmark-columns=min,max,mean teste09.py … linhas omitidas … -------------- benchmark: 1 tests --------------1/1) Name (time in ns) Min Max Mean ------------------------------------------------ teste_soma 84.2402 441.6500 88.0371 ------------------------------------------------ … linhas omitidas … Ref. https://pypi.org/project/pytest-benchmark/
  22. 27.

    Como medir o consumo de CPU? [2] def somatorio(numeros): resultado

    = 0 for numero in numeros: resultado += numero return resultado def teste_somatorio(benchmark): # realiza benchmark da função de somatorio result = benchmark(somatorio, [10, 20]) # verifica se a somatorio deu o resultado esperado assert result == 30 Ref. https://pypi.org/project/pytest-benchmark/
  23. 28.

    Como medir o consumo de CPU? [2] def teste_sum(benchmark): #

    realiza benchmark da função de sum result = benchmark(sum, [10, 20]) # verifica se a sum deu o resultado esperado assert result == 30 Ref. https://pypi.org/project/pytest-benchmark/
  24. 29.

    Como medir o consumo de CPU? [2] $ # Executando

    o código $ pytest --benchmark-columns=min,max,mean teste10.py … linhas omitidas … ------------------------------- benchmark: 2 tests Name (time in ns) Min Max Mean -------------------------------------------------------------------------------- teste_sum 83.8301 (1.0) 668.2900 (1.0) 87.8679 (1.0) teste_somatorio 172.8968 (2.06) 1,607.2761 (2.41) 189.3247 (2.15) -------------------------------------------------------------------------------- … linhas omitidas … Ref. https://pypi.org/project/pytest-benchmark/
  25. 30.

    Dica final Antes de procurar soluções mirabolantes procure na standard

    library (built-in) do próprio Python! Just Python! :-) Aqui nesta palestra temos exemplos que isso funciona muito bem (built-in): • import timeit • from sys import getsizeof • import cProfile Mas vale lembrar que coisas extras trazem facilidades: • pip install memory_profiler • pip install pytest-benchmark
  26. 31.

    Referências Códigos contidos nos slides: https://gist.github.com/rafaelhenrique/f18bbfafd3c9066f3eca3f1f024937ed Trabalhe conosco: https://www.99jobs.com/olist Code

    Highlighter https://github.com/romannurik/SlidesCodeHighlighter Módulo timeit https://docs.python.org/3/library/timeit.html Otimização de memória RAM https://stackoverflow.com/questions/14372006/variables-memory-size-in-python https://pypi.org/project/memory_profiler/ Otimização de CPU https://docs.python.org/3/library/profile.html https://pypi.org/project/pytest-benchmark/