[PYTHON] Einführung in die Optimierung

Mal sehen, wie man einen Profiler in Python verwendet, um ein Programm zeitlich zu steuern und zu beschleunigen.

Was ist Optimierung?

Was ist Programmoptimierung?

Dieses Mal konzentrieren wir uns auf die Verkürzung der Bearbeitungszeit

Was braucht Zeit?

Lassen Sie uns die Verarbeitungszeit des Programms messen.

Angenommen, Sie haben zwei Programme, die 5 Sekunden dauern, versuchen Sie, mit dem Befehl time zu messen.

python


% time ./wait.py
./wait.py  0.02s user 0.02s system 0% cpu 5.057 total
% time ./busy.py
./busy.py  5.01s user 0.02s system 99% cpu 5.038 total

In beiden Fällen dauert es vom Beginn bis zum Ende des Programms insgesamt 5 Sekunden, aber die Situation ist etwas anders.

Werfen wir einen Blick auf die tatsächlich verwendete Quelle:

wait.py


#!/usr/bin/env python

import time

def main():
    time.sleep(5)

if __name__ == '__main__':
    main()

busy.py


#!/usr/bin/env python

import time

def main():
    start = time.time()
    while time.time() - start < 5:
        pass

if __name__ == '__main__':
    main()

Der Umgang mit Zeit ist anders

Im Allgemeinen verbringen Programme ihre Zeit mit Dingen wie:

Verbessern Sie, wie Sie Ihre Zeit verbringen

Finden Sie einen Engpass

Wo im Programm könnten Sie sich verbessern?

Wie findet man

Log

Protokollausgabe der Zeitdifferenz vor und nach der Verarbeitung

python


start = time.time()
some_func()
print "%f sec" % (time.time() - start)

python


start = time.clock()
some_func()
print "%f sec" % (time.clock() - start)

cProfile

Eines der Tools namens "Profiler", das mit Python geliefert wird.

Von der Kommandozeile

Mit einem Programm ausführen, das wie der Befehl time als Argument ausgeführt werden soll

python


% python -m cProfile wait.py
         4 function calls in 5.002 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.001    0.001    5.002    5.002 wait.py:3(<module>)
        1    0.000    0.000    5.001    5.001 wait.py:5(main)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    5.001    5.001    5.001    5.001 {time.sleep}
Artikel Bedeutung des Wertes
ncalls Anzahl der Anrufe
tottime Zeitaufwand(Beinhaltet nicht, was genannt wurde)
percall Zeitaufwand pro Anruf(tottime/ncalls)
cumtime Zeitaufwand(Einschließlich dessen, was Sie angerufen haben)
percall Zeitaufwand pro Anruf(cumtime/ncalls)

Wenn Sie cProfile.py über die Befehlszeile ausführen

In Code einbetten

wait_profile.py


#!/usr/bin/env python

import cProfile
import time

def main():
    time.sleep(5)

if __name__ == '__main__':
    cProfile.run("main()", "wait.prof")
% python -c "import pstats; pstats.Stats('wait.prof').strip_dirs().sort_stats(-1).print_stats()"
Fri Jun 17 00:25:58 2016    wait.prof

         4 function calls in 5.005 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    5.005    5.005 <string>:1(<module>)
        1    0.000    0.000    5.005    5.005 wait_profile.py:6(main)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    5.005    5.005    5.005    5.005 {time.sleep}

So fahren Sie mit der Optimierung fort

Verbessern Sie nicht funktionale Anforderungen, während Sie die funktionalen Anforderungen beibehalten

Wie zu empfehlen

Lass es uns versuchen

Fibonacci-Folge

fib.py


#!/usr/bin/env python

def fib(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fib(n-2) + fib(n-1)

if __name__ == '__main__':
    assert fib(30) == 832040

python


% time ./fib.py
python fib.py  0.52s user 0.01s system 98% cpu 0.540 total
% python -m cProfile fib.py
         2692539 function calls (3 primitive calls) in 1.084 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.084    1.084 fib.py:3(<module>)
2692537/1    1.084    0.000    1.084    1.084 fib.py:3(fib)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

In diesem Beispiel wird fib zu oft aufgerufen. (M / N Tottime bedeutet M rekursive Aufrufe und N nicht rekursive Aufrufe)

Beachten Sie auch, dass letzteres länger dauert, wenn die mit dem Zeitbefehl gemessene Ausführungszeit ohne Profil (0,540 s) und die Ausführungszeit mit Profil (1,084 s) verglichen werden.

Verbessern Sie die Leistung bei gleichzeitiger Beibehaltung der Funktionalität

Eigentlich versuchen

fib_optimized.py


#!/usr/bin/env python

cache = {}

def fib(n):
    if n in cache:
        return cache[n]
    if n == 0:
        cache[n] = 0
    elif n == 1:
        cache[n] = 1
    else:
        cache[n] = fib(n-2) + fib(n-1)
    return cache[n]

if __name__ == '__main__':
    assert fib(30) == 832040

python


% python -m cProfile fib_optimized.py
         61 function calls (3 primitive calls) in 0.000 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 fib_optimized.py:3(<module>)
     59/1    0.000    0.000    0.000    0.000 fib_optimized.py:5(fib)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

Die Anzahl der Anrufe wurde reduziert und die Gesamtzeit verkürzt!

Das zweite Beispiel. Eine Funktion, die die Summe von Anfang bis Ende nimmt, wird unter Verwendung der Standardfunktionssumme implementiert.

takesum.py


#!/usr/bin/env python

def takesum(beg, end):
    "take sum of beg, beg+1, ..., end"
    assert beg <= end
    i = beg
    xs = []
    while i <= end:
        xs.append(i)
        i += 1
    return sum(xs)

if __name__ == '__main__':
    assert takesum(0, 10000000) == 50000005000000

python


% python -m cProfile takesum.py
         10000005 function calls in 3.482 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.076    0.076    3.482    3.482 takesum.py:3(<module>)
        1    2.418    2.418    3.405    3.405 takesum.py:3(takesum)
 10000001    0.878    0.000    0.878    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.109    0.109    0.109    0.109 {sum}

Überlegen Sie, wie Sie die Verarbeitungszeit reduzieren können.

Zusammenfassung

Recommended Posts

Einführung in die Optimierung
Erste Schritte mit Android!
1.1 Erste Schritte mit Python
Erste Schritte mit apache2
Erste Schritte mit Python
Erste Schritte mit Numpy
Erste Schritte mit Spark
Erste Schritte mit Python
Erste Schritte mit Pydantic
Erste Schritte mit Jython
Erste Schritte mit Django 2
Übersetzen Erste Schritte mit TensorFlow
Einführung in Python-Funktionen
Einführung in Tkinter 2: Button
Erste Schritte mit Go Assembly
Erste Schritte mit PKI mit Golang ―― 4
Erste Schritte mit Python Django (1)
Erste Schritte mit Python Django (4)
Erste Schritte mit Python Django (3)
Einführung in Python Django (6)
Erste Schritte mit Django mit PyCharm
Erste Schritte mit Python Django (5)
Erste Schritte mit Python Responder v2
Einführung in Git (1) History-Speicher
Erste Schritte mit Python-Webanwendungen
Erste Schritte mit Python für PHPer-Klassen
Erste Schritte mit Sparse Matrix mit scipy.sparse
Erste Schritte mit Julia für Pythonista
Erste Schritte mit Python Grundlagen von Python
Erste Schritte mit der Cisco Spark REST-API
Beginnend mit USD unter Windows
Erste Schritte mit genetischen Python-Algorithmen
Erste Schritte mit Python 3.8 unter Windows
Erste Schritte mit Python für PHPer-Funktionen
Erste Schritte mit der CPU-Diebstahlzeit
Grale fangen an
Erste Schritte mit Python3 # 1 Grundkenntnisse erlernen
Erste Schritte mit Python Web Scraping Practice
Erste Schritte mit Python für PHPer-Super Basics
Erste Schritte mit Python Web Scraping Practice
Erste Schritte mit Dynamo von Python Boto
Erste Schritte mit Lisp für Pythonista: Ergänzung
Erste Schritte mit Heroku, Bereitstellen der Flaschen-App
Erste Schritte mit TDD mit Cyber-dojo bei MobPro
Erste Schritte mit Python mit 100 Klopfen bei der Sprachverarbeitung
Django 1.11 wurde mit Python3.6 gestartet
MongoDB-Grundlagen: Erste Schritte mit CRUD mit JAVA
Erste Schritte mit der japanischen Übersetzung des Keras Sequential-Modells
[Übersetzung] Erste Schritte mit Rust für Python-Programmierer
Straßeninstallation durch Optimierung
Django Erste Schritte Teil 2 mit dem Eclipse Plugin (PyDev)
Beginnen Sie mit MicroPython
Erste Schritte mit AWS IoT in Python
Beginnen Sie mit Mezzanine
Erste Schritte mit Pythons Ast-Modul (Verwenden von NodeVisitor)