asyncio教程
简介
asyncio是一种使用单线程单进程的的方式实现并发的工具。asyncio提供的框架以事件循环(event loop)为中心,程序开启一个无限的循环,程序会把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。
event loop
Eventloop实例提供了注册、取消和执行任务(Task)和回调的方法。
把一些异步函数注册到这个事件循环上,事件循环会循环执行这些函数(但同时只能执行一个),当执行到某个函数时,如果它正在等待I/O返回,事件循环会暂停它的执行去执行其他的函数;当某个函数完成I/O后,会恢复下次循环到它的时候继续执行。因此,这些异步函数可以协同(Cooperative)运行
协程(Coroutine)
协程本质上是一个函数,特点是在代码块中可以将执行权交给其他协程。
import asyncio
async def a():#async定义协程
print('Suspending a')
await asyncio.sleep(0)#await表示调用协程,sleep 0并不会真的sleep,但却交出控制权
print('Resuming a')
async def b():
print('In b')
async def main():
await asyncio.gather(a(), b())#并发运行任务,在这里表示协同的执行a和b两个协程
if __name__ == '__main__':
asyncio.run(main())
#运行结果:表示在运行协程a的过程中让出了控制权,并发执行协程b,之后再返回执行a
#Suspending a
#In b
#Resuming a
Future
future是一个数据结构,表示还未完成的工作结果。事件循环可以监视Future对象是否完成。从而允许一个协程等待另一协程完成一些工作
Task
Task是Future的一个子类,它知道如何包装和管理一个协程的执行。任务所需的资源可用时,事件循环会调度任务允许,并生成一个结果,从而可以由其他协程消费。
task = asyncio.ensure_future(a())
#或者是task = loop.create_task(a())
print(task.done())#False
await task#真正开始执行
print(task.done())#True
执行协程的例子
#下面是一个错误的例子
import asyncio
import time
async def say_after(delay, what):#定义了一个协程函数
await asyncio.sleep(delay)
print(what)
async def main():#同样也是协程
print(f"started at {time.strftime('%X')}")
await say_after(1, 'hello')#顺序执行两个协程
await say_after(2, 'world')
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
#结果是并没有实现两个协程并发执行,因为等待的时间有3s
async def main():#惯用写法是在协程main中执行其他的协程
task1 = asyncio.create_task(#将协程函数用Task封装
say_after(1, 'hello'))
task2 = asyncio.create_task(
say_after(2, 'world'))
print(f"started at {time.strftime('%X')}")
# Wait until both tasks are completed (should take
# around 2 seconds.)
await task1#也是顺序执行两个协程
await task2
print(f"finished at {time.strftime('%X')}")
#结果是真正实现了两个协程的并发执行,因为执等待了2s
#注意错误的写法,下面的不能实现协程的并发执行
#await asyncio.create_task(say_after(1, 'hello'))
#await asyncio.create_task(say_after(2, 'world'))
#使用下面的形式也可以实现协程的并发执行
async def main():
await asyncio.gather(say_after(1, 'hello'), say_after(2, 'world'))
async def main():
await asyncio.wait([say_after(1, 'hello'), say_after(2, 'world')])
可等待对象await
可以在await语句中使用的对象,有三种协程,Future和Task,只是通常情况下没有必要在应用代码中创建 Future 对象。
import asyncio
async def nested():
return 42
async def main():
nested()#此协程并没有执行
print(await nested()) #使用await才会真正执行
asyncio.run(main())
import asyncio
async def nested():
return 42
async def main():
task = asyncio.create_task(nested())
await task
asyncio.run(main())
函数签名
coroutine asyncio.sleep(delay, result=None)
#阻塞 delay 秒,如果指定了 result,则当协程完成时将其返回给调用者。
#sleep() 总是会挂起当前任务,以允许其他任务运行。
#将 delay 设为 0 将提供一个经优化的路径以允许其他任务运行。 这可供长期间运行的函数使用以避免在函数调用的全过程中阻塞事件循环。