python协程
背景:
当发送一个网络请求时,受限于网络环境影响可能需要等待一段时间,但此时cpu是空闲的,此时可以利用cpu处理另外的运算,直到收到服务端的回应继续运算。协程就是处理这种情形的,因此协程需要底层的支持。
原理:
这部分是个人对于协程原理的理解,等执行任务A到达一个不需要cpu但耗时的操作时,可以将A当前状态保存,并返回一个特殊的对象a,这个对象在A的操作完成时发送一个信号使得A可以继续,由于A此时返回了a,释放了当前资源,任务B就可以运行,任务A,B可以理解为task,而对象a可以理解为furture。
实践:
1.多次请求同一url
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import aiohttp import asyncio import datetime
async def test(url): async with aiohttp.ClientSession() as session: async with session.get(url) as resp: print(resp.status, datetime.datetime.now())
async def main(): for i in range(10): print(i) asyncio.create_task(test("https://google.com"))
loop = asyncio.get_event_loop() loop.create_task(main()) loop.run_forever()
|
该例子会输出0~9,说明等待响应并没有阻碍下一次请求。需要注意await是让出运行权限,并不会创建task,以下写法不会产生异步的效果
1 2 3 4
| async def main(): for i in range(10): print(i) await asyncio.create_task(test("https://google.com"))
|
await不会将task放入循环,反而会让出权限等待task执行完毕
2.占有权限
1 2 3 4 5 6 7 8 9 10 11 12 13
| async def a(): print("a start") await asyncio.sleep(1) print("a end")
async def b(): print("b start") time.sleep(3) print("b end")
loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.wait([a(), b()]))
|
以下是结果,可以看出a让出使用权限后,即使furture完成,也只能等待b让出权限后才能执行。
1 2 3 4
| a start b start b end a end
|
并且更换a,b的顺序
1
| loop.run_until_complete(asyncio.wait([b(), a()]))
|
会使协程变成串行失去意义,可以猜想实际loop中有两个队列,一个为task队列,另一个为信号队列,用于指示当前task让出权限后执行的task。