2009-10-18 18 views
15

Ich versuche, eine Instanzmethode zum Profil, also habe ich etwas getan, wie:Rückgabewert bei der Verwendung von cProfile

import cProfile 

class Test(): 

    def __init__(self): 
     pass 

    def method(self): 
     cProfile.runctx("self.method_actual()", globals(), locals()) 

    def method_actual(self): 
     print "Run" 

if __name__ == "__main__": 
    Test().method() 

Aber jetzt Probleme entstehen, wenn ich „Methode“ soll einen Wert zurückgeben, der berechnet wird, durch "method_actual". Ich möchte "method_actual" nicht wirklich zweimal aufrufen.

Gibt es einen anderen Weg, etwas, das threadsicher sein kann? (In meiner Anwendung werden die cProfile Daten auf Datendateien von einem der args Namen gespeichert, so dass sie nicht bekommen, clobbered und ich kann sie später kombinieren.)

Antwort

26

entdeckte ich, dass Sie dies tun können:

prof = cProfile.Profile() 
retval = prof.runcall(self.method_actual, *args, **kwargs) 
prof.dump_stats(datafn) 

Der Nachteil ist, dass es undokumentiert ist.

+2

Brilliant! Das sieht perfekt aus - aber was ist Datafn? –

+0

@ JonathanHartley - Der Dateiname für die Datei IIRC. – detly

+0

Ah, danke. Ich dachte 'Fn' meinte Funktion, nicht Dateiname. –

6

Ich hatte mit dem gleichen Problem zu kämpfen und verwendet eine Wrapper-Funktion, um über direkte Rückgabewerte zu bekommen. Statt

cP.runctx("a=foo()", globals(), locales()) 

ich eine Wrapper-Funktion

def wrapper(b): 
    b.append(foo()) 

und den Aufruf der Wrapper-Funktion Profil

b = [] 
cP.runctx("wrapper(b)", globals(), locals()) 
a = b[0] 

das Ergebnis der foo der Berechnung aus dem heraus param Extrahieren (b) danach .

+0

Funktioniert wie ein Charme. –

18

Eine Option für jeden beliebigen Code:

import cProfile, pstats, sys 
pr = cProfile.Profile() 
pr.enable() 

my_return_val = my_func(my_arg) 

pr.disable() 
ps = pstats.Stats(pr, stream=sys.stdout) 
ps.print_stats() 

von https://docs.python.org/2/library/profile.html#profile.Profile

+0

Sie könnten sogar einen kleinen Context Manager mit dem Contextlib 'contextmanager' Decorator erstellen. – detly

+0

Ich bekomme 'Random Listing Reihenfolge wurde verwendet '- Wie kann ich Listing Reihenfolge angeben? –

+1

ps.sort_stats ('kumulativ') – marsh

1

genommen denke ich @detly die .runcall() ist im Grunde die beste Antwort, aber der Vollständigkeit halber, ich wollte nur @ThomasH ‚s nehmen Antwort-Funktion, unabhängig zu sein:

def wrapper(b, f, *myargs, **mykwargs): 
    try: 
     b.append(f(*myargs, **mykwargs)) 
    except TypeError: 
     print 'bad args passed to func.' 

# Example run 
def func(a, n): 
    return n*a + 1 

b = [] 
cProfile.runctx("wrapper(b, func, 3, n=1)", globals(), locals()) 
a = b[0] 
print 'a, ', a 
1

ich ein Dekorateur erstellt:

import cProfile 
import functools 
import pstats 

def profile(func): 

    @functools.wraps(func) 
    def inner(*args, **kwargs): 
     profiler = cProfile.Profile() 
     profiler.enable() 
     try: 
      retval = func(*args, **kwargs) 
     finally: 
      profiler.disable() 
      with open('profile.out', 'w') as profile_file: 
       stats = pstats.Stats(profiler, stream=profile_file) 
       stats.print_stats() 
     return retval 

    return inner 

Ihre Funktion oder Methode mit ihm dekorieren:

@profile 
def somefunc(...): 
    ... 

Nun wird diese Funktion profiliert werden.

Alternativ, wenn Sie die rohen, unbearbeiteten Profildaten möchten (zB weil Sie die hervorragende graphische Zuschauer RunSnakeRun darauf laufen soll), dann gilt:

import cProfile 
import functools 
import pstats 

def profile(func): 

    @functools.wraps(func) 
    def inner(*args, **kwargs): 
     profiler = cProfile.Profile() 
     profiler.enable() 
     try: 
      retval = func(*args, **kwargs) 
     finally: 
      profiler.disable() 
      profiler.dump_stats('profile.out') 
     return retval 

    return inner 

Dies ist eine geringfügige Verbesserung auf mehreren Die anderen Antworten auf dieser Seite.

Verwandte Themen