Вы можете полностью избежать этой проблемы, если передадите timeit
функцию вместо строки. В этом случае функция выполняется в обычном глобальном и закрывающем окружении. Так:
timeit.timeit(lambda: function(x))
Или, если хотите:
timeit.timeit(partial(function, x))
(Подробнее см. здесь. Обратите внимание, что для этого требуется Python 2.6+, поэтому, если вам нужно 2.3-2.5, вы не можете использовать этот трюк.)
Как сказано в документации: «Обратите внимание, что временные издержки в этом случае немного больше из-за дополнительных вызовов функций».
Это означает, что он заставляет сам timeit
работать медленнее. Например:
>>> def f(): pass
>>> timeit.timeit('timeit.timeit("f()", setup="from __main__ import f")', setup='import timeit', number=1000)
91.66315175301861
>>> timeit.timeit(lambda: timeit.timeit(f), number=100)
94.89793294097762
Однако на фактические результаты это не влияет:
>>> timeit.timeit(f, number=100000000)
8.81197881908156
>>> timeit.timeit('f()', setup='from __main__ import f', number=100000000)
8.893913001054898
(В редких случаях, когда это происходит, это обычно означает, что та или иная версия не тестировала функцию так, как она будет вызываться в вашем реальном коде, или тестировала неправильное закрытие или подобное.)
Обратите внимание, что фактическое время, затрачиваемое внутри функции, здесь составляет около 88 секунд, поэтому мы почти удвоили накладные расходы на код синхронизации ... но все равно добавили только 3% к общему времени тестирования. И чем менее тривиален f
, тем меньше будет эта разница.
person
abarnert
schedule
18.09.2013