python运行的单进程单线程的程序,并不能提升运算速度,比较适合需要处理等到的任务,如网络通信,
asyncio的核心是一个event loop,就像一个大脑,面向很多task,然后决定执行哪个task,同时执行的任务只能有一个,不存在系统级的上下文切换,它需要每一个task主动告诉event loop:我这边结束了,可以让别的task开始,不存在竞争冒险的问题,可以明确知道每一个任务什么时候停止运算了。
首先要理解coroutine和task:
Coroutine function:上图中的async def main就是,python里面所有async开头的东西都叫Coroutine function,定义了一个Coroutine的过程,Coroutine function调用的时候返回Coroutine object。执行到core = main()的时候并不会执行程序,只会返回Coroutine object。
Coroutine object。
如何运行Coroutine function里面的代码呢?
第一,进入async模式,进入even loop
Asyncio.run(),参数为coroutine会建立even loop,把Coroutine 变成这个even loop里面的第一个task,event loop 建立之后就会去找哪个task可以执行。
Event loop的核心是它有很多很多task,然后它决定哪个task要运行,所有很重要的一件事情是当已经处于async模式下的时候,如何增加task。
第二,把Coroutine 变成task,让它可以排队执行的方法:
(asyncio.sleep返回的东西也是一个coroutine)
方法1:await,await coroutine 的时候,会发生以下事情:
- 这个coroutine被包装成一个task,并且被告诉event loop这里有个新的task;
- 控制权交还。它会告诉event loop 现在这个task需要等到say_after task 完成之后我才能继续,建立了这种依赖关系;
- 会yeild出去,会告诉event loop,我这个task现在干不了,先让别的task去干。
综上所述,这段代码的过程为:asyncio.run()把main()返回的coroutine变成task,event loop里面就这一个task,然后执行到await say_after(1, ’hello’),这个coroutine被包装成一个task,并且被告诉event loop这里有个新的task;它会告诉event loop 现在这个main task需要等到say_after task 完成之后我才能继续,say_after task里面类似。这里需要3秒完成整个main()程序。
问题:为啥等待1s和等待2s不能一起等呢?
这是协程的意义。
create_task()可以解决这个问题,其参数为coroutine,create_task()会把传进来的coroutine变成一个task,并且把task注册到event loop里面,也就是说它分担了await coroutine 的一部分功能。他把coroutine包装成一个task,并且告诉event loop 说这个task已经可以开始执行了。但是现在event loop并没有办法执行这个task,因为控制权还在main的手里这个时候main趁着自己有控制权,它就做了第二个task2,也是告诉main这里还有一个新的task,say_task2也可以运行了,在这之后开始await task1,await task2,告诉event loop:我需要这个task完成。这里只需要2秒完成整个main()程序。Await task1的时候event loop里面实际有3个task,task1和event loop 说完“我要等1s才能完成”后,event loop发现task2还可以执行,于是执行task2,所以两个task可以同时等待。(task可以放权,coroutine不能放权。)
如果有很多task,可以用gather()函数,它的参数是若干个coroutine或者task,甚至是future。它会返回future,这个future也可以用await。这里ret返回是一个list,就是每个task执行完后的返回值。
总结:如果代码里面没有等待这件事的话,协程对这个代码是没有帮助的,分清coroutine和task,coroutine只有被变成task才开始被执行,要能知道coroutine什么时候被隐式地变成了task。最后拿到coroutine的返回值需要用await,一个变量=await coroutine object。