2009-10-18 34 views
15

Próbuję profil metodę instancji, więc zrobiłem coś takiego:Zwracana wartość podczas korzystania 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() 

ale teraz pojawiają się problemy, gdy chcę „metoda”, aby powrócić do wartości, która jest obliczana przez "method_actual". Naprawdę nie chcę wywoływać "method_actual" dwukrotnie.

Czy istnieje inny sposób, który może być bezpieczny dla wątków? (W mojej aplikacji, dane cProfile są zapisywane pliki danych nazwanych przez jednego z argumentami, żeby nie dostać niszczona i mogę połączyć je później).

Odpowiedz

26

odkryłem, że można to zrobić:

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

Wadą jest to, że jest nieudokumentowana.

+2

Genialny! To wygląda idealnie - ale czym jest "datafn"? –

+0

@ JonathanHartley - Nazwa pliku IIRC pliku danych. – detly

+0

Ah, dzięki. Myślałem, że "fn" oznacza funkcję, a nie nazwę pliku. –

6

Zmagałem się z tym samym problemem i użyłem funkcji otoki, aby uzyskać wartości bezpośredniego zwrotu. Zamiast

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

utworzyć funkcję otoki

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

i profil wywołanie funkcji otoki

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

wydobycia wynik obliczeń Foo z param out (b) później .

+0

Działa jak urok. –

18

Opcja dla dowolnej kodu:

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() 

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

+0

Można nawet utworzyć małego menedżera kontekstu za pomocą 'decorlib''' menedżera kontekstowego '. – detly

+0

Otrzymuję polecenie "Kolejność losowań" - jak określić kolejność aukcji? –

+1

ps.sort_stats ("zbiorcza") – marsh

1

myślę @detly .runcall() jest po prostu najlepszą odpowiedzią, ale pod względem kompletności, chciałem wziąć @ThomasH „s odpowiadać będzie niezależna funkcja:

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

stworzyłem dekorator:

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 

Udekoruj funkcję lub metodę z nim:

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

Teraz, gdy funkcja zostanie profilowane.

Alternatywnie, jeśli chcesz dane surowe, nieprzetworzone profil (np bo chcesz uruchomić doskonałą graficznym RunSnakeRun na nim), a następnie:

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 

Jest to niewielka poprawa na kilka inne odpowiedzi na tej stronie.

Powiązane problemy