профилирование метода класса в Python с использованием cProfile? - PullRequest
31 голосов
/ 20 декабря 2010

Я бы хотел профилировать метод функции в Python, используя cProfile.Я попробовал следующее:

import cProfile as profile

# Inside the class method...
profile.run("self.myMethod()", "output_file")

Но это не работает.Как я могу назвать self.method с помощью «run»?

Ответы [ 5 ]

47 голосов
/ 20 декабря 2010

РЕДАКТИРОВАТЬ: Извините, не понял, что вызов профиля был в метод класса.

run просто пытается exec строку, которую вы передаете.Если self не привязан ни к чему в области действия профилировщика, который вы используете, вы не сможете использовать его в run!Используйте метод runctx для передачи локальных и глобальных переменных в области вызова профилировщика:

>>> import time
>>> import cProfile as profile
>>> class Foo(object):
...     def bar(self):
...             profile.runctx('self.baz()', globals(), locals())
...
...     def baz(self):
...             time.sleep(1)
...             print 'slept'
...             time.sleep(2)
...
>>> foo = Foo()
>>> foo.bar()
slept
         5 function calls in 2.999 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    2.999    2.999 <stdin>:5(baz)
        1    0.000    0.000    2.999    2.999 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        2    2.999    1.499    2.999    1.499 {time.sleep}

Обратите внимание на последнюю строку: time.sleep - это то, что нужновремя.

23 голосов
/ 20 декабря 2010

Использовать декораторы крючков

http://pypi.python.org/pypi/profilehooks

2 голосов
/ 20 декабря 2010

Я бы не рекомендовал профилировать одну подпрограмму, потому что это означает, что нужно заранее знать, что там есть проблема.

Фундаментальный аспект проблем с производительностью - это хитрость.Они не там, где вы думаете, потому что если бы они были, вы бы уже решили их.

Лучше запустить всю программу с реалистичной рабочей нагрузкой и позволить методике профилирования сказать вам, где проблемы.

Вот пример , где профилирование находит проблему, а не там, где ожидается.

1 голос
/ 18 октября 2017

Если ваша функция в профиле возвращает значения, вам нужно немного изменить отличный ответ от @katrielalex:

...             profile.runctx('val = self.baz()', globals(), locals())
...             print locals()['val']
0 голосов
/ 09 января 2019

Если вы хотите создать накопительный профилировщик, то есть запускать функцию несколько раз подряд и просматривать сумму результатов.

вы можете использовать этот cumulative_profiler декоратор:

import cProfile, pstats

class _ProfileFunc:
    def __init__(self, func, sort_stats_by):
        self.func =  func
        self.profile_runs = []
        self.sort_stats_by = sort_stats_by

    def __call__(self, *args, **kwargs):
        pr = cProfile.Profile()
        pr.enable()  # this is the profiling section
        retval = self.func(*args, **kwargs)
        pr.disable()
        self.profile_runs.append(pr)
        ps = pstats.Stats(*self.profile_runs).sort_stats(self.sort_stats_by)
        return retval, ps

def cumulative_profiler(amount_of_times, sort_stats_by='time'):
    def real_decorator(function):
        def wrapper(*args, **kwargs):
            nonlocal function, amount_of_times, sort_stats_by  # for python 2.x remove this row

            profiled_func = _ProfileFunc(function, sort_stats_by)
            for i in range(amount_of_times):
                retval, ps = profiled_func(*args, **kwargs)
            ps.print_stats()
            return retval  # returns the results of the function
        return wrapper

    if callable(amount_of_times):  # incase you don't want to specify the amount of times
        func = amount_of_times  # amount_of_times is the function in here
        amount_of_times = 5  # the default amount
        return real_decorator(func)
    return real_decorator

Пример

профилирование функции baz

import time

@cumulative_profiler
def baz():
    time.sleep(1)
    time.sleep(2)
    return 1

baz()

baz выполнено 5 раз и напечатано так:

         20 function calls in 15.003 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10   15.003    1.500   15.003    1.500 {built-in method time.sleep}
        5    0.000    0.000   15.003    3.001 <ipython-input-9-c89afe010372>:3(baz)
        5    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

указав количество раз

@cumulative_profiler(3)
def baz():
    ...
...