Сколько накладных расходов делают декораторы для вызова функций Python
Я играл с декоратором времени для моего приложения pylons, чтобы предоставлять информацию о времени полета для определенных функций. Я сделал это, создав декоратор и просто привязав его к любой функции в контроллере, который я хочу выполнить по времени.
Было указано, однако, что декораторы могут добавить к вызову достаточное количество накладных расходов и что они работают на 2-3 раза медленнее, чем некорректированная функция.
Во-первых, я ожидал бы, что выполнение декорированной функции займет больше времени, чем неупорядоченный, но я ожидаю, что накладные расходы будут в тысячные доли секунды и будут незначительными по сравнению с вызовом вставки SQL. Сам декоратор выполняет простые простые вычисления времени, используя time.time() и некоторую очень простую агрегацию.
Делают ли декораторы значительные накладные расходы на систему? Я не могу найти ничего, чтобы поддержать это.
Ответы
Ответ 1
Накладные расходы, добавленные с помощью декоратора, должны быть только одним дополнительным вызовом функции.
Работа, выполняемая декоратором, не является частью служебных данных, так как ваша альтернатива заключается в том, чтобы добавить эквивалентный код к украшенному объекту.
Таким образом, возможно, что функция decorate занимает в два раза больше времени, но это потому, что декоратор выполняет важную работу, которая занимает примерно одно и то же время, чтобы весело провести время, как непривязанная функция.
Ответ 2
Важно знать, что декоратор имеет простой эффект:
@decorator
def f():
…
- это просто синтаксический сахар для
def f():
…
f = decorator(f)
Таким образом, если декоратор ничего не делает, у вас нет накладных расходов при вызове декорированной функции (вызов decorator(f)
занимает немного времени, хотя), как в
decorator = lambda func: func
@decorator
def f():
…
Если декоратор что-либо делает, вы получаете только время, затраченное декоратором. Обычно это включает дополнительный вызов функции (функции декорированной функции), как в
def decorator(func):
def decorated_func():
print "Before calling function", func # Some overhead (but that normal)
func() # This will be a second function call, after the call to decorated_func()
return decorated_func
Таким образом, само по себе украшение функции не добавляет больших накладных расходов для того, что вы хотите сделать: единственные очевидные накладные расходы, которые вы могли бы в принципе удалить, заключались бы в том, чтобы не вызвать func()
в украшенной функции, а вместо этого скопировать его полный кода, но четкость кода будет страдать (разборчивость и гибкость - вот некоторые из причин, по которым декораторы существуют в первую очередь).
Ответ 3
Делают ли декораторы значительные накладные расходы на систему? Я не могу найти ничего, чтобы поддержать это.
Они добавляют почти никаких измеримых накладных расходов. Ноль.
Важно отметить, что декоратор работает один раз, чтобы создать украшенную функцию.
Один раз.
У декорированной функции есть две части.
Там нет реальных накладных расходов. Вы можете - с некоторой осторожностью - быть в состоянии измерить накладные расходы на один дополнительный вызов функции и возврата как часть украшенной функции, но это почти неизмеримо мало. И это, вероятно, гораздо меньше, чем альтернативный дизайн, который не использует украшения.