Сотрудник указал мне, что with
заявление может быть медленным. Таким образом, я измерил и, действительно, требуется 20 раз дольше, чтобы получить значение от функции contextmanager
, чем от генератора в Python 2.7 и даже в 200 раз дольше в PyPy 2.6.Почему contextmanager медленный
Почему это так? Можно ли переписать contextlib.contextmanager()
, чтобы работать быстрее?
Для справки:
def value_from_generator():
def inner(): yield 1
value, = inner()
return value
def value_from_with():
@contextmanager
def inner(): yield 1
with inner() as value:
return value
И тайминги:
$ python -m timeit 'value_from_generator()'
10000000 loops, best of 3: 0.169 usec per loop
$ python -m timeit 'value_from_with()'
100000 loops, best of 3: 3.04 usec per loop
Тест, который обновляет контекстный менеджер с нуля каждый раз, не является особенно хорошим тестовым примером для стоимости _using_ менеджера контекста. Как правило, украшенная функция '@ contextmanager' определяется один раз, но используется много раз; это как отказ от использования 'class'es и функций, потому что использование' dict 'и помещение всего inline происходит быстрее. – ShadowRanger
@ShadowRanger вы правы. Похоже, что «contextmanager» вносит большой вклад в замедление. И после этого замена декоратора на класс контекстного менеджера, поскольку @krrr предлагает ускорить работу даже больше. –