gpt4 book ai didi

python - 在 Python 中进行协同程序尾调用时,使用或避免协同程序是否更符合 Pythonic(和/或性能)?

转载 作者:太空狗 更新时间:2023-10-29 23:57:18 24 4
gpt4 key购买 nike

在 Python 3.5+ 中,我经常遇到这样的情况:我有很多嵌套协程只是为了调用一些深度协程的东西,其中 await在大多数函数中仅出现在尾调用中,如下所示:

import asyncio

async def deep(time):
await asyncio.sleep(time)
return time

async def c(time):
time *= 2
return await deep(time)

async def b(time):
time *= 2
return await c(time)

async def a(time):
time *= 2
return await b(time)

async def test():
print(await a(0.1))

loop = asyncio.get_event_loop()
loop.run_until_complete(test())
loop.close()

那些功能a , b , 和 c可以写成返回协程的常规函数​​,而不是协程本身,如下所示:

import asyncio

async def deep(time):
await asyncio.sleep(time)
return time

def c(time):
time *= 2
return deep(time)

def b(time):
time *= 2
return c(time)

def a(time):
time *= 2
return b(time)

async def test():
print(await a(0.1))

loop = asyncio.get_event_loop()
loop.run_until_complete(test())
loop.close()

哪种方式更 Pythonic?哪种方式性能更高?哪种方式以后其他人更容易维护?

编辑——绩效衡量

作为性能测试,我删除了 await asyncio.sleep(time)来自 deep 的行并定时迭代 1,000,000 次 await a(0.1) .在我的 CPython 3.5.2 测试系统上,第一个版本用了大约 2.4 秒,第二个版本用了大约 1.6 秒。所以看起来让所有东西都成为协程可能会有性能损失,但这肯定不是一个数量级。或许具有更多 Python 代码分析经验的人可以创建适当的基准并最终解决性能问题。

最佳答案

使用第一个:您不仅可以明确显示可以暂停代码的位置(放置 await 的位置),还可以获得所有相关的好处,例如显示有用的执行流程的回溯。

要查看差异,请更改您的 deep 协程以抛出一些错误:

async def deep(time):
await asyncio.sleep(time)
raise ValueError('some error happened')
return time

对于第一个片段,您将看到此输出:

Traceback (most recent call last):
File ".\tmp.py", line 116, in <module>
loop.run_until_complete(test())
File ".\Python36\lib\asyncio\base_events.py", line 466, in run_until_complete
return future.result()
File ".\tmp.py", line 113, in test
print(await a(0.1))
File ".\tmp.py", line 110, in a
return await b(time)
File ".\tmp.py", line 106, in b
return await c(time)
File ".\tmp.py", line 102, in c
return await deep(time)
File ".\tmp.py", line 97, in deep
raise ValueError('some error happened')
ValueError: some error happened

但仅针对第二个片段:

Traceback (most recent call last):
File ".\tmp.py", line 149, in <module>
loop.run_until_complete(test())
File ".\Python36\lib\asyncio\base_events.py", line 466, in run_until_complete
return future.result()
File ".\tmp.py", line 146, in test
print(await a(0.1))
File ".\tmp.py", line 130, in deep
raise ValueError('some error happened')
ValueError: some error happened

如您所见,第一个回溯可以帮助您看到“真实的”(有用的)执行流程,而第二个则不能。

编写代码的第一种方法也更易于维护:想象一下您曾经理解 b(time) 还应该包含一些异步调用,例如 await asyncio.sleep(time)。在第一个片段中,可以直接放置此调用而无需任何其他更改,但在第二个片段中,您必须重写代码的许多部分。

关于python - 在 Python 中进行协同程序尾调用时,使用或避免协同程序是否更符合 Pythonic(和/或性能)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44223090/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com