深入Asyncio(四)Coroutines

本文详细介绍了Python中协程的概念,包括asyncio模块的使用,asyncdef和await关键字的语法,以及如何通过send()和throw()方法控制协程的运行。同时,文章还探讨了如何在不同的协程之间进行切换,以及如何处理协程中的异常。
摘要由CSDN通过智能技术生成

Coroutines

asyncio在3.4版本添加到Python中,但通过async defawait关键字创建coroutines的语法是3.5才加入的,在这之前,人们把generators当作coroutines来使用,在一些老的语法中,你可以看到用@asyncio.coroutine之类的装饰器加yield的句式,在本文中,请摒弃过去的写法。

async def关键字

>>> async def f():    # 1
...     return 123
>>> type(f)    # 2
<class 'function'>
>>> import inspect    # 3
>>> inspect.iscoroutinefunction(f)
True
  1. 这是声明coroutine的最简单方式;
  2. 与生成器函数的判定一样,coroutine也会被判定为协程函数,只有在调用这个函数时才能获得协程,就如生成器一样;
  3. 标准库中的检查模块可以提供比type方法更好的内省能力。

正是由于在3.4版本用生成器当作协程来使用,所以在3.5版本中,async def的用法以及效果与生成器几乎相同。我们通过代码来观察Python如何在不同协程中切换,首先先看下如何获得return的值。

当coroutine return的时候,将会抛出一个StopIteration异常。

>>> async def f():
...     return 123
>>> coro = f()
>>> try:
...     coro.send(None)    # 1
... except StopIteration as e:
...     print('The answer was: ', e.value)    # 2
The answer was:  123
  1. coroutine通过发送None来启动,这就是loop在背后做的事;
  2. 协程返回时抛出StopIteration异常,可以通过异常的value属性访问返回值。

协程的开始和结束是通过send()和StopIteration来定义的,loop负责在背后做这些事,开发者只需要为loop安排task即可。

await关键字

await关键字总是接收一个参数,其类型必须是awaitable的,必须是如下两种之一:
1. 一个coroutine;
2. 一个实现了__await__()方法的对象,这个方法必须返回一个迭代器。

async def f():
    await asyncio.sleep(1.0)
    return 123
async def main():
    result = await f()  # 1
    return result
  1. 这里调用了f函数返回了一个coroutine。

在开始学习loop之前,了解一下如何向协程提供异常很有用,异常通常用于取消协程,在task.cancel()时,loop在内部使用coro.throw()来抛出一个asyncio.CancelledError

>>> coro = f()  # 使用上面的协程
>>> coro.send(None)
<Future pending>
>>> coro.throw(Exception, 'hello')  # 通过throw方法提供一个异常和值,该异常将在await处产生
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
Exception: hello
>>> async def f():
...     try:
...             while True: await asyncio.sleep(0)
...     except asyncio.CancelledError:
...             print('I was cancelled!')
...     else:
...             return 111
>>> coro = f()
>>> coro.send(None)
>>> coro.send(None)
>>> coro.throw(asyncio.CancelledError)
I was cancelled!
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration   # 正是由于内部捕捉了CancelledError,这个协程得以正常退出
>>> import asyncio
>>> async def f():
...     try:
...             while True: await asyncio.sleep(0)
...     except asyncio.CancelledError:
...             print('Cancelled')
...             while True: await asyncio.sleep(0)  # 跳转到另一个协程上去了
...     else: return 1
>>> coro = f()
>>> coro.send(None)
>>> coro.throw(asyncio.CancelledError)
Cancelled
>>> coro.send(None)

目前为止的代码中,都是通过手动调用send(None)throw(asyncio.CancelledError)来模拟loop的,下一章开始学习用loop来自动处理。

>>> async def f():
...     await asyncio.sleep(0)
...     return 123
>>> loop = asyncio.get_event_loop()
>>> loop.run_until_complete(f())
123

转载于:https://www.cnblogs.com/ikct2017/p/9828993.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值