Python异步编程使用asycn
和await
两个关键词进行修饰。其中asycn
关键词修饰过程,而await
修饰操作本身。
EventLoop(事件循环)
Python异步编程的核心是维护若干个事件循环,学过操作系统的可以把事件简单地认为是“进程”。Python的事件循环维护若干个Task(协程),当Task被阻塞或者Task完成了,就从Task池(我起的名字)中获取下一个可以用的Task来执行。你可以通过get_running_loop()
和get_event_loop()
来获取当前的事件循环。区别是前者如果没有正在运行的事件循环则会引发 RuntimeError并且只能由协程或回调来调用。后者如果没有正在运行的事件循环择新建一个事件循环。
Task
事件循环本质就是管理Task。Task是一次协程的一次执行。协程使用asycn
关键词进行修饰。这种函数最大特点是执行可以暂停,交出执行权。在asycn
修饰的函数里面可以加上await
修饰的asycn
函数,就像这样:
1 | import asyncio |
当执行到await这一步的时候,就暂停当前Task命令的执行,反而去执行别的命令(就相当于阻塞)。这个时候会有人问,await修饰的那段任务执行情况是怎么样的呢,是作为一个新的Task放入事件循环中?其实不是,await代表异步执行,你可以简单地理解成开一个新的协程去做这件事情。这个协程首先把当前Task给暂停了,换一个新的Task。等那个新的协程把事情做完了,把之前那个被暂停的Task抓到Task池里面。其核心就是把IO密集型的任务进行重组,在IO等待的时候做点别的。
那至于Python如何平衡这个协程和新协程,就是内核做的事情,程序员不需要思考这件事。你可以认为,在程序员的角度中,就是做到需要等待的任务,就交给别人先占用CPU,我等完了我再来占用CPU。异步的目的就是并发执行。并发执行计算和IO,并发执行若干个任务。(这里我猜有一种机制,可以让计算,也就是CPU操作和IO一起执行,其实硬件上是可以实现的,有一种叫做DMA的机器可以实现IO和计算分离,具体的实现可以去学学,但是我目前就只知道用法)
Push task to eventloop
我们可以使用asyncio.run()
来执行一个异步任务,也可以使用asyncio.gather()
打包若干个Task进行执行。
Get the return value from task
我们可以使用task.result()
来统一返回,可以配合barrier一起使用
1 | if __name__ == '__main__': |