web-dev-qa-db-fra.com

Existe-t-il un moyen simple de comparer le script python?

Habituellement, j'utilise la commande Shell time. Mon but est de tester si les données sont petites, moyennes, grandes ou très grandes, combien de temps et d'utilisation de la mémoire seront.

Des outils pour Linux ou juste python pour ce faire?

66
noomz

Jetez un œil à timeit , le python et pycallgraph .

timeit

def test():
    """Stupid test function"""
    lst = []
    for i in range(100):
        lst.append(i)

if __== '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test"))

Essentiellement, vous pouvez le passer python en tant que paramètre de chaîne, et il s'exécutera dans le nombre de fois spécifié et affichera le temps d'exécution. Les bits importants des documents:

timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)

Créez une instance Timer avec l'instruction donnée, setup code et timer fonction et exécutez sa méthode timeit avec nombre exécutions.

... et:

Timer.timeit(number=1000000)

Heure nombre exécutions de l'instruction principale. Cela exécute l'instruction de configuration une fois, puis retourne le temps nécessaire pour exécuter l'instruction principale un certain nombre de fois, mesuré en secondes sous forme de flottant. L'argument est le nombre de fois dans la boucle, par défaut à un million. L'instruction principale, l'instruction d'installation et la fonction de temporisation à utiliser sont transmises au constructeur.

Remarque

Par défaut, timeit désactive temporairement garbage collection Pendant le chronométrage. L'avantage de cette approche est qu'elle rend les timings indépendants plus comparables. Cet inconvénient est que le GC peut être un élément important des performances de la fonction mesurée. Si c'est le cas, GC peut être réactivé comme première instruction de la chaîne setup. Par exemple:

timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit()

Profilage

Le profilage vous donnera une beaucoup idée plus détaillée de ce qui se passe. Voici "l'exemple instantané" de les documents officiels :

import cProfile
import re
cProfile.run('re.compile("foo|bar")')

Ce qui vous donnera:

      197 function calls (192 primitive calls) in 0.002 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.001    0.001 <string>:1(<module>)
     1    0.000    0.000    0.001    0.001 re.py:212(compile)
     1    0.000    0.000    0.001    0.001 re.py:268(_compile)
     1    0.000    0.000    0.000    0.000 sre_compile.py:172(_compile_charset)
     1    0.000    0.000    0.000    0.000 sre_compile.py:201(_optimize_charset)
     4    0.000    0.000    0.000    0.000 sre_compile.py:25(_identityfunction)
   3/1    0.000    0.000    0.000    0.000 sre_compile.py:33(_compile)

Ces deux modules devraient vous donner une idée de l'endroit où rechercher les goulots d'étranglement.

Aussi, pour vous familiariser avec la sortie de profile, jetez un œil à ce post

pycallgraph

Ce module utilise graphviz pour créer des callgraphs comme celui-ci:

callgraph example

Vous pouvez facilement voir les chemins les plus utilisés par couleur. Vous pouvez soit les créer à l'aide de l'API pycallgraph, soit à l'aide d'un script packagé:

pycallgraph graphviz -- ./mypythonscript.py

Les frais généraux sont cependant assez considérables. Ainsi, pour les processus déjà longs, la création du graphique peut prendre un certain temps.

94
exhuma

J'utilise un simple décorateur pour chronométrer le func

def st_time(func):
    """
        st decorator to calculate the total time of a func
    """

    def st_func(*args, **keyArgs):
        t1 = time.time()
        r = func(*args, **keyArgs)
        t2 = time.time()
        print "Function=%s, Time=%s" % (func.__name__, t2 - t1)
        return r

    return st_func
26
Danyun Liu

Le module timeit était lent et bizarre, alors j'ai écrit ceci:

def timereps(reps, func):
    from time import time
    start = time()
    for i in range(0, reps):
        func()
    end = time()
    return (end - start) / reps

Exemple:

import os
listdir_time = timereps(10000, lambda: os.listdir('/'))
print "python can do %d os.listdir('/') per second" % (1 / listdir_time)

Pour moi, ça dit:

python can do 40925 os.listdir('/') per second

Il s'agit d'une sorte primitive de benchmarking, mais c'est assez bon.

12
Sam Watkins

Je fais habituellement un rapide time ./script.py pour voir combien de temps cela prend. Cela ne vous montre cependant pas la mémoire, du moins pas par défaut. Vous pouvez utiliser /usr/bin/time -v ./script.py pour obtenir beaucoup d'informations, y compris l'utilisation de la mémoire.

10
Martin Ueding

Memory Profiler pour tous vos besoins en mémoire.

https://pypi.python.org/pypi/memory_profiler

Exécutez une installation pip:

pip install memory_profiler

Importez la bibliothèque:

import memory_profiler

Ajoutez un décorateur à l'article que vous souhaitez profiler:

@profile
def my_func():
    a = [1] * (10 ** 6)
    b = [2] * (2 * 10 ** 7)
    del b
    return a

if __== '__main__':
    my_func()

Exécutez le code:

python -m memory_profiler example.py

Recevoir la sortie:

 Line #    Mem usage  Increment   Line Contents
 ==============================================
 3                           @profile
 4      5.97 MB    0.00 MB   def my_func():
 5     13.61 MB    7.64 MB       a = [1] * (10 ** 6)
 6    166.20 MB  152.59 MB       b = [2] * (2 * 10 ** 7)
 7     13.61 MB -152.59 MB       del b
 8     13.61 MB    0.00 MB       return a

Les exemples proviennent des documents, liés ci-dessus.

3
John Von Neumann

Jetez un œil à nez et à l'un de ses plugins, celui-ci en particulier.

Une fois installé, nose est un script sur votre chemin, et que vous pouvez appeler dans un répertoire contenant quelques scripts python:

$: nosetests

Cela va chercher dans tous les fichiers python dans le répertoire courant et exécutera toute fonction qu'il reconnaît comme test: par exemple, il reconnaît toute fonction avec le mot test_ dans son nom comme test .

Vous pouvez donc simplement créer un script python appelé test_yourfunction.py et y écrire quelque chose comme ceci:

$: cat > test_yourfunction.py

def test_smallinput():
    yourfunction(smallinput)

def test_mediuminput():
    yourfunction(mediuminput)

def test_largeinput():
    yourfunction(largeinput)

Ensuite, vous devez exécuter

$: nosetest --with-profile --profile-stats-file yourstatsprofile.prof testyourfunction.py

et pour lire le fichier de profil, utilisez cette ligne python:

python -c "import hotshot.stats ; stats = hotshot.stats.load('yourstatsprofile.prof') ; stats.sort_stats('time', 'calls') ; stats.print_stats(200)"
3
dalloliogm

Attention timeit est très lent, il faut 12 secondes sur mon processeur moyen pour simplement l'initialiser (ou peut-être exécuter la fonction). vous pouvez tester cette réponse acceptée

def test():
    lst = []
    for i in range(100):
        lst.append(i)

if __== '__main__':
    import timeit
    print(timeit.timeit("test()", setup="from __main__ import test")) # 12 second

pour une chose simple, j'utiliserai time à la place, sur mon PC, il retournera le résultat 0.0

import time

def test():
    lst = []
    for i in range(100):
        lst.append(i)

t1 = time.time()

test()

result = time.time() - t1
print(result) # 0.000000xxxx
0
cieunteung

Le moyen facile de tester rapidement n'importe quelle fonction est d'utiliser cette syntaxe: %timeit my_code

Par exemple :

%timeit a = 1

13.4 ns ± 0.781 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
0
Arcyno