说实话,我目前对这一块的理解并不深刻,只能是通过我自己的使用进行总结,当然,随着时间的推移和更新,这篇文章的内容会越来越对。
参考资料
举个例子
假设一个厨房正在生产菜。每一个菜后面都有一个做菜的师傅,每一个做菜的师傅都有一个切配、杂手等。
切配来切各种食材,杂手准备各种厨具,同时做菜的师傅至少掌管 2
个锅。
如果将该灶台抽象为一个线程,那么做菜的师傅可以称之为一个事件循环(Event Loop),而锅可以认为是事件循环中的任务,切配、杂手是处理任务的。
- 一个菜名送过来「任务注册到事件循环中」
- 大厨看到菜名「事件循环开始工作」
- 切配准备「
IO
准备」 - 切配准备好了,告知大厨「唤醒相关任务」
- 大厨完成这道菜「任务结束」
那异步的优势是什么呢?
- 可以有多个任务注册到事件循环中「有多个锅」
- 如果遇到
IO
堵塞,可以执行其他事件循环的任务「当切配准备时,大厨可以做已经准备好的菜」 - 成本低,上下文切换快「如果你换一个灶台,还需要跑来跑去,但是,你灶台有两个锅」
除了上述之外,还有几个隐藏的点
- 每一个线程都可以有一个事件循环「灶台后面有一个大厨」
- 每一个线程只能有一个事件循环「一道菜只能由一个大厨做」
事件循环
1 | while 1: |
事件循环就是在 loop
没有结束的时候,会一直循环里面已经注册的任务,直到遇到特定条件来终止循环。
和 while
不同的是,里面的 task
有很多状态,结束、运行、挂起等。
一个网络请求任务注册到事件循环中,当网络正在请求的时候,事件循环会去执行其他任务,当请求过来之后,会唤醒该任务。
另外一个重要的事情是,协程可以简单的理解为某一道菜,它是依附于大厨,即事件循环的,不能独立执行。
如果,你想做菜,那么你需要准备一个大厨。
如果事件循环结束,比如,你在线程中创建一个事件循环,后面再调用的话是非法的。大厨走了,你给菜名并不能做菜。
不同线程的事件循环并不能使用,线程能用只有自己的事件循环。将面点给炒菜的,是不行的。
1 | import asyncio |