协程
-
协程不是真是存在的,程序员人为创造出来的(上下文切换的技术)
-
协程:可以成为微线程,是一种用户态的上下文切换技术,简而言之,其实就是通过一个线程实现代码块相互切换执行。
def func1(): print(1) print(2) print(3) def fun2(): print(3) print(4) func1() func2()
实现协程
-
greenlet
-
yield关键字
-
asyncio 装饰器
-
async、 await关键字(3.5)【⭐】
1.1 Greenlet 实现协程
-
pip install greenlet
-
1.2 yield 关键字
1.3asyncio
python 3.4以及之后
import asyncio @asyncio.coroutine def func1(): print(1) yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务 print(2) @asyncio.coroutine def func2(): print(3) yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务 print(4) tasks = [ asyncio.ensure_future( func1() ), asyncio.ensure_future( func2() ) ] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks))
注意:遇到io阻塞会自动i切换
3.5 async & await关键字
import asyncio async def func1(): print(1) await asyncio.sleep(2) print(2) async def func2(): print(3) await asyncio.sleep(2) print(4) tasks = [ asyncio.ensure_future(func1()), asyncio.ensure_future(func2()) ] loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait(tasks))
2.协程的意义
在一个线程中如果遇到IO等待时间,线程不会傻等,空闲的时间再去干点其他事
案例:下载三张图片
-
同步:一个接一个的执行
-
异步:一个跳一个
3.异步编程
3.1事件循环
理解成为一个死循环,去检测并执行代码
# 伪代码 任务列表 =[任务1,任务2,任务3,..] while True: for 就绪任务 in 可执行的任务列表: 执行已就绪的任务 for 已完成的任务 in 已完成的任务列表: 在任务列表中移除 已完成的任务
improt asyncio # 去生成或获取一个事件循环 loop= asyncio.get_event_loop() # 将任务放到‘任务列表’ loop.run_until_complete(任务)
3.2 快速上手
协程函数,定义函数时 async def 函数名。
协程对象,执行 协程函数()得到协程对象。
anync def func() : #协程函数 pass result = func() #协程对象
注意:执行协程函数创建协程对象,函数内部代码不运行
如果想要运行协程函数内部代码, 必须要将写成对象交给事件循环来处理。
anync def func() : #协程函数 printf("少女起到中") result = func() #协程对象 # 去生成或获取一个事件循环 loop= asyncio.get_event_loop() # 将任务放到‘任务列表’ loop.run_until_complete(result) # asyncio.run(result) #python3.7
import asyncio async def func(): print("Eva...") result = func() asyncio.run(result)
3.3 await
await + 可等待的对象 (协程对象、future、task对象->IO等待)]
import asyncio async def func(): print("来玩啊") await asyncio.sleep(2) #等待执行其他 print("结束") asyncio.run(func())
import asyncio async def others(): print("start") await asyncio.sleep(2) print('end') return '返回值' async def func(): print("执行协程函数内部代码") # 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。 response = await others() print("IO请求结束,结果为:", response) asyncio.run( func() )
3.4 Task对象
帮助我们在事件循环中添加多个任务
Tasks用于并发调度协程,通过asyncio.create_task(协程对象)
的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。
除了使用 asyncio.create_task()
函数以外,还可以用低层级的 loop.create_task()
或 ensure_future()
函数。不建议手动实例化 Task 对象。
本质上是将协程对象封装成task对象,并将协程立即加入事件循环,同时追踪协程的状态。
注意:asyncio.create_task()
函数在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用低层级的 asyncio.ensure_future()
函数。
示例一
import asyncio async def func(): print(1) await asyncio.sleep(2) print(2) return "返回值" async def main(): print("main开始") # 创建协程,将协程封装到一个Task对象中并立即添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。 task1 = asyncio.create_task(func()) # 创建协程,将协程封装到一个Task对象中并立即添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。 task2 = asyncio.create_task(func()) print("main结束") # 当执行某协程遇到IO操作时,会自动化切换执行其他任务。 # 此处的await是等待相对应的协程全都执行完毕并获取结果 ret1 = await task1 ret2 = await task2 print(ret1, ret2) asyncio.run(main())