Joh*_*eks 6 python coroutine python-asyncio
在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()
Run Code Online (Sandbox Code Playgroud)
这些功能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()
Run Code Online (Sandbox Code Playgroud)
哪种方式更像Pythonic?哪种方式更高效?以后哪种方式更容易维护?
作为性能测试,我await asyncio.sleep(time)从deep1,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
Run Code Online (Sandbox Code Playgroud)
对于第一个片段,您将看到此输出:
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
Run Code Online (Sandbox Code Playgroud)
但仅限第二个片段:
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
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,第一个回溯可以帮助您查看"真实"(和有用的)执行流程,而第二个则不会.
编写代码的第一种方法也更好维护:想象一下你曾经理解过b(time)还应该包含一些异步调用,比如await asyncio.sleep(time).在第一个代码段中,可以直接放置此调用而无需任何其他更改,但在第二个代码中,您将不得不重写代码的许多部分.
| 归档时间: |
|
| 查看次数: |
167 次 |
| 最近记录: |