首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么contextmanager速度慢?

为什么contextmanager速度慢?
EN

Stack Overflow用户
提问于 2016-01-19 09:04:47
回答 2查看 1.3K关注 0票数 5

一位同事向我指出,with的陈述可能很慢。因此,我用Python2.7测量了--实际上,从contextmanager函数中获得值所需的时间是Python2.7中的生成器的20倍,在PyPy 2.6中甚至是后者的200倍。

为什么会这样呢?重写contextlib.contextmanager()可以运行得更快吗?

供参考:

代码语言:javascript
复制
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

和时间安排:

代码语言:javascript
复制
$ 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
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-01-19 14:52:38

使用分析器和contextlib的源代码,我发现:

代码语言:javascript
复制
value_from_with:
 ncalls  tottime  cumtime  filename:lineno(function)
1000000    1.415    4.802  value_from_with  # 1sec more than value_from_generator, likely caused by with statement
1000000    1.115    1.258  contextlib.py:37(__init__)  # better doc string of context manager instance
1000000    0.656    0.976  contextlib.py:63(__exit__)  # optional exception handling
1000000    0.575    1.833  contextlib.py:124(helper)  # "wrapped" in decorator
2000000    0.402    0.604  {built-in method next}  # why it's so expensive?
1000000    0.293    0.578  contextlib.py:57(__enter__)  # a next() call to the generator in try&except block (just for error msg)
2000000    0.203    0.203  inner1
1000000    0.143    0.143  {built-in method getattr}  # better doc string, called by __init__

value_from_generator:
 ncalls  tottime  cumtime  filename:lineno(function)
1000000    0.416    0.546  value_from_generator
2000000    0.130    0.130  inner2

它告诉我们:从生成器中解压缩比使用next()更快;函数调用很昂贵;异常处理是expensive...so --比较是不公平的,这种分析只是为了好玩。

它还告诉我们,每次执行"with“块时,都会创建上下文管理器的实例(几乎不可避免)。除此之外,contextmanager还做了一些工作来说服我们。如果您真的想优化它,可以编写上下文管理器类,而不是使用修饰器。

配置代码:

代码语言:javascript
复制
def inner1(): yield 1

def value_from_generator():
    value, = inner1()
    return value

# inner should not be created again and again
@contextmanager
def inner2(): yield 1

def value_from_with():
    with inner2() as value:
        return value
票数 4
EN

Stack Overflow用户

发布于 2016-01-19 15:10:39

这两个工具的用途“略有不同”,因此比较它们的性能并不能真正显示什么。

Contextmanagers允许您在with块中执行代码之前和之后执行一些操作。常见的用途是在开始时占用资源,执行任务,执行清理,即数据库连接、文件访问等。

生成器允许您编写函数,以保存调用之间的状态。通常用于节省不必要的计算(特别是时间)上的资源,并在不立即存储所有操作结果的情况下节省内存。因此,主要的用途是用于计算。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34872535

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档