【问题标题】:Python "conditional" async methodPython“条件”异步方法
【发布时间】:2022-01-23 05:52:14
【问题描述】:

我很好奇当我有这样的功能时行为/性能开销是什么:

async def slow_function(some_resource):
    if some_resource in cache.keys():
        return cache[some_resource]
    return await requests.get(some_resource)

在我们以某种方式缓存“some_resource”的情况下,不会执行“await”。在这种情况下,“异步”的开销是多少?由于没有达到“等待”语句,它实际上是零开销吗?或者,当调用“异步”函数时,无论如何都会有一些不可避免的开销?

【问题讨论】:

  • 这样的性能问题比你想象的要简单。设置一个测试用例。测量它。

标签: python asynchronous


【解决方案1】:

抱歉,这不是实际问题的答案,但我认为这已经涵盖了

您的代码存在不小的性能问题,但与异步无关。

检查一个键是否在缓存中,然后在缓存中查找该键比访问该键并捕获 KeyError 慢

(这里只是看缓存有key的“快乐”路径)

>>> import timeit
>>> timeit.timeit('try: cache[x]\nexcept KeyError: pass', setup='cache = {i: i for i in range(500)}; x = 5')
0.0273395610274747
>>> timeit.timeit('if x in cache.keys(): cache[x]', setup='cache = {i: i for i in range(500)}; x = 5')
0.08461441402323544

这样的东西可能会表现得更好

async def slow_function(some_resource):
    try:
        return cache[some_resource]
    except KeyError:
        return await requests.get(some_resource)

【讨论】:

  • 对,我想用这个例子来说明的想法是有一个“等待”并不总是被执行。
  • 此外,很大程度上取决于密钥是否在缓存中。任何低于 80% 或 90% 的机会,最好使用.get()。异常生成__traceback__ 的开销很高。
【解决方案2】:

几乎 0 开销。

异步将像正常功能一样继续。开销是当您到达await 时,会在链中产生未来。

本质上,每次你await 一个未完成的Future 时,事件循环都必须绑定到它并继续一个需要一系列操作的新循环。如果您的 await 立即返回而不等待未来,则事件循环不会循环,并且该函数会像任何其他生成器函数一样正常继续。

其余的开销是普通函数调用和生成器初始化之间的差异(因为协同程序的实现方式完全相同)。虽然有一些开销,甚至可能是正常函数调用的两倍或三倍(主要与生成器本身的创建有关),但与在每个事件循环周期中发生大量指令的大约 50 或 60 个完整函数调用相比,它可以忽略不计.

【讨论】:

    猜你喜欢
    • 2021-11-17
    • 2019-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-19
    • 1970-01-01
    相关资源
    最近更新 更多