Профилирование Python с использованием line_profiler — умный способ удалить операторы @profile на лету?

Я хочу использовать отличный line_profiler, но только иногда. Чтобы это работало, я добавляю

@profile

перед каждым вызовом функции, например.

@profile
def myFunc(args):
    blah
    return

и выполнить

kernprof.py -l -v mycode.py args

Но я не хочу каждый раз вводить декораторы @profile вручную, потому что большую часть времени я хочу выполнять код без них, и я получаю исключение, если пытаюсь их включить, например.

mycode.py args

Есть ли счастливая среда, в которой я могу динамически удалять декораторы на основе некоторого переключателя/аргумента условия, без необходимости делать что-то вручную и/или слишком сильно изменять каждую функцию?


person jtlz2    schedule 14.08.2013    source источник
comment
Я бы спросил себя, действительно ли мне нужно профилировать так часто, что мне нужна такая поддержка. Я не говорю, что вы делаете или не делаете, так что вам не нужно отвечать. Я просто нашел вариант использования немного удивительным.   -  person msw    schedule 14.08.2013
comment
Код занимает много времени (часы на данный момент...) для выполнения, поэтому сейчас я хочу убить двух зайцев одним выстрелом, получая результаты и профилируя одновременно. Я полагаю, что рассматриваю профилирование как непрерывный процесс (поскольку я новичок в этом/воодушевлен этим), поэтому я бы не стал просто использовать его во (многих) функциях, объявить его выполненным и удалить все декораторы.   -  person jtlz2    schedule 15.08.2013
comment
Я бы не позволил чему-то занять несколько часов, не попробовав это. Это ничего не стоит и точно говорит вам, что происходит.   -  person Mike Dunlavey    schedule 29.08.2015
comment
@jtlz2 Вы также можете обернуть функции и методы класса в профиль (возможно, в отдельный скрипт профилирования) и полностью избежать добавления декораторов @profile, как описано здесь (stackoverflow.com/a/43376466/5874320).   -  person tdube    schedule 03.09.2017


Ответы (4)


Вместо того, чтобы удалять строки декоратора @profile, предоставьте свою собственную сквозную неактивную версию.

Вы можете добавить следующий код в свой проект где-нибудь:

try:
    # Python 2
    import __builtin__ as builtins
except ImportError:
    # Python 3
    import builtins

try:
    builtins.profile
except AttributeError:
    # No line profiler, provide a pass-through version
    def profile(func): return func
    builtins.profile = profile

Импортируйте это перед любым кодом, использующим декоратор @profile, и вы можете использовать код с активным профилировщиком линий или без него.

Так как фиктивный декоратор является сквозной функцией, это не влияет на производительность выполнения (влияет только производительность импорта почти незначительно).

Если вам не нравится возиться со встроенными модулями, вы можете сделать это отдельным модулем; скажи profile_support.py:

try:
    # Python 2
    import __builtin__ as builtins
except ImportError:
    # Python 3
    import builtins

try:
    profile = builtins.profile
except AttributeError:
    # No line profiler, provide a pass-through version
    def profile(func): return func

(без назначения builtins.profile) и используйте from profile_support import profile в любом модуле, использующем декоратор @profile.

person Martijn Pieters    schedule 14.08.2013

Вам вообще не нужно импортировать __builtins__/builtins или LineProfiler, вы можете просто полагаться на NameError при попытке поиска profile:

try:
    profile
except NameError:
    profile = lambda x: x

Однако это необходимо включить в каждый файл, который использует profile, но он не изменяет (навсегда) глобальное состояние (встроенные функции) Python.

person MSeifert    schedule 13.05.2017

Комментарий, который превратился в вариант ответа @Martijin Pieters.

Я предпочитаю вообще не привлекать __builtin__. Без комментария было бы практически невозможно, чтобы кто-то еще догадался, что line_profiler замешан, не зная об этом априори.

Глядя на kernprof строка 199, достаточно создать экземпляр LineProfiler.

try:
    from line_profiler import LineProfiler
    profile = LineProfiler()
except ImportError:
    def profile(func):
        return func

Импорт (явный) лучше, чем глобальное изменение builtins (неявный). Если декораторы профилирования постоянные, то их происхождение должно быть понятно из самого кода.

При наличии line_profiler описанный выше подход будет оборачивать декорированные функции профилировщиками при каждом запуске, независимо от того, запускается ли kernprof. Этот побочный эффект может быть нежелательным.

person Ioannis Filippidis    schedule 29.08.2015

Я использую следующую модифицированную версию с Python 3.4.

try:
    import builtins
    profile = builtins.__dict__['profile']
except KeyError:
    # No line profiler, provide a pass-through version
    def profile(func): return func
person ChrisP    schedule 27.05.2015