关键字
yield
先来说yield关键字,它可以作为生产器的关键字。在早期的python版本中,可以通过生成器来实现协程。从这可以看出生成器和协程有共同之处,都可以暂停函数执行,保留上下文。这正是生成器,协程和普通函数的区别,普通函数不能暂停执行,只能从一个点入,一个点出。通过yield产生返回一个生成器对象,每次调用next或者send方法的时候,生成器从yield处恢复,直到遇到下一个yield(经常用于循环)或者函数return。生成器主要用于惰性计算,比如对大型数据集进行逐项处理的时候,节约内存。
async
协程(Corouting)同样可以暂停,让出控制权,并在适当时候恢复。它通过 async 语法定义。像await,async for 和 async with只能在协程内部使用。由于早期协程是通过生成器来实现的,通过send方法来实现接收数据的功能,所以和现在的async协程容易搞混。Python3.5后开始引入 async,Python3.7后正式成为了关键字。 来看官网的这个例子
import asyncio
async def nested():
return 42
async def main():
nested()
print(await nested())
asyncio.run(main())
如果直接使用 nested(), 会出现一行Warning日志RuntimeWarning: coroutine 'nested' was never awaited,不会影响整个程序的运行。查看它们的类型, 可以看出 nested 是一个函数,调用该函数返回一个 coroutine。nested() 的作用是返回一个 coroutine, 而不是运行 nested 函数的内部代码。从这可以看出 async 实际上可以理解为装饰器。
print(type(nested)) # <class 'function'>
print(type(nested())) # <class 'coroutine'>
await
如果一个对象可以使用 await 语句,那么就说它是可等待对象。常见的三种可等待对象有三种,Coroutines, Task, Futures。await的主要作用是暂停协程,交出控制权。在下面的例子中await asyncio.sleep(2), 在这里等待asyncio.sleep(2)运行完成再恢复。
import asyncio
async def my_coroutine():
print("开始执行协程"
await asyncio.sleep(2)
await asyncio.sleep(2)
print("协程恢复执行")
async def main():
await my_coroutine()
await my_coroutine()
asyncio.run(main())
>>>
17:49:12
开始执行协程
协程恢复执行
开始执行协程
协程恢复执行
17:49:20
可以看出代码是顺序运行的,并不是并发运行,这样因为await只是用来暂停喝恢复协程的。想要并发运行,需要把协程添加到事件循环队列中。