协程
协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行
协程意义:在一个线程中如果遇到IO等待时间,线程不会傻傻等,利用空闲的时候再去干点其他事。
一、效果演示
1.1 正常执行
from timeimport sleepfrom timeimport time
start= time()deffunc1():print(1)
sleep(1)print(2)deffunc2():print(3)
sleep(1)print(4)
func1()
func2()
end= time()# 输出1234print(end-start)# 2.028127908706665
1.2 使用asynico
import asynciofrom timeimport time
start= time()asyncdeffunc1():print(1)await asyncio.sleep(1)print(2)asyncdeffunc2():print(3)await asyncio.sleep(1)print(4)
tasks=[
func1(),
func2()]
loop= asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end= time()# 输出 1324print(end-start)# 1.010634422302246
可以很明显的看到程序在遇到i0费时操作时,asyncio的效率有多高
学习使用
3.1 事件循环
事件循环就是把你创建好的函数,加入到任务列表,事件循环负责监听任务列表,当执行这个函数遇到费时操作时,事件循环就会控制跳到其他可执行的任务,当没有可执行的任务就会等待当前任务执行完毕,只有全部任务都执行完毕,才会退出循环。
# 伪代码
任务列表=[ 任务1, 任务2, 任务3,...]whileTrue:
可执行的任务列表,已完成的任务列表= 去任务列表中检查所有的任务,将'可执行'和'已完成'的任务返回for 就绪任务in 可执行的任务列表:
执行已就绪的任务for 已完成的任务in 已完成的任务列表:
在任务列表中移除 已完成的任务
如果 任务列表 中的任务都已完成,则终止循环
import asyncio# 去生成或获取一个事件循环
loop= asyncio.get_event_loop()# 将任务放到`任务列表`
loop.run_until_complete(任务)
asyncio.wait()
控制任务
通过asyncio.wait()可以控制多任务
asyncio.wait()是一个协程,不会阻塞,立即返回,返回的是协程对象。传入的参数是future或协程构成的可迭代对象。最后将返回值传给run_until_complete()加入事件循环
3.2 携程函数
协程函数,定义函数的时候使用async def 函数名
协程对象,执行写成函数()得到的学成对象
# d定义协程函数asyncdeffunc():pass# 获取写成对象
result= func()print(result)# <coroutine object func at 0x000002326168AD40>
注意:执行协程函数创建协程对象,函数内部代码不会执行。
如果想要运行协程函数内部代码,必须要讲协程对象交给事件循环来处理。
import asyncioasyncdeffunc():print("执行协程函数!")
result= func()
loop= asyncio.get_event_loop()
loop.run_until_complete(result)
python3.7有个更简便的方法
import asyncioasyncdeffunc():print("执行协程函数!")
result= func()# loop = asyncio.get_event_loop()# loop.run_until_complete( result )
asyncio.run(result)# python3.7
3.3 await
await + 可等待的对象(协程对象、Future、Task对象 -> IO等待)
示例一
import asyncioasyncdeffunc():print("开始")
response=await asyncio.sleep(2)print("结束",response)
asyncio.run( func())
示例二:
import asyncioasyncdefothers():print("start")await asyncio.sleep(2)print('end')return'返回值'asyncdeffunc():print("执行协程函数内部代码")# 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。
response=await others()print("IO请求结束,结果为:", response)asyncdeffunc1():print('func1')
tasks=[
func(),
func1()]
asyncio.run(asyncio.wait(tasks))
3.4 Task对象
Tasks用于并发调度协程,通过asyncio.create_task(协程对象)
的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。除了使用asyncio.create_task()
函数以外,还可以用低层级的loop.create_task()
或ensure_future()
函数。不建议手动实例化 Task 对象。
注意:asyncio.create_task()
函数在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用低层级的asyncio.ensure_future()
函数。
示例一:
import asyncioasyncdeffunc():print(1)await asyncio.sleep(2)print(2)return"返回值"asyncdefmain():print("main开始")# 创建Task对象,将当前执行func函数任务添加到事件循环。
task1= asyncio.create_task( func())# 创建Task对象,将当前执行func函数任务添加到事件循环。
task2= asyncio.create_task( func())print("main结束")# 当执行某协程遇到IO操作时,会自动化切换执行其他任务。# 此处的await是等待相对应的协程全都执行完毕并获取结果
ret1=await task1
ret2=await task2print(ret1, ret2)
asyncio.run( main())
示例二:
import asyncioasyncdeffunc():print(1)await asyncio.sleep(2)print(2)return"返回值"asyncdefmain():print("main开始")# name给任务起个名字
task_list=[
asyncio.create_task(func(), name='n1'),
asyncio.create_task(func(), name='n2')]print("main结束")# done是任务列表返回的集合,pending未完成任务的集合
done, pending=await asyncio.wait(task_list, timeout=None)print(done)# {<Task finished name='n1' coro=<func() done, defined at C:/Users/86166/Deskto/a.py:4> result='返回值'>, <Task finished name='n2' coro=<func() done, defined at C:/Users/86166/Desktop/a.py:4> result='返回值'>}
asyncio.run(main())
示例三:
import asyncioasyncdeffunc():print(1)await asyncio.sleep(2)print(2)return"返回值"
task_list=[
func(),
func(),]
done,pending= asyncio.run( asyncio.wait(task_list))print(done)