一、知识准备
● 相对于 run_until_complete
,改动并不大,就是将入口函数重新封装了一下,基础知识主要还是 run_until_complete
的内容
● asyncio.run是Python3.7之后新增的入口函数
二、环境准备
组件 | 版本 |
python | 3.7.7 |
三、 run
的实现
先来看下官方asyncio的使用方法:
|># more main.py
import asyncio
async def hello():
print('enter hello ...')
return 'world'
if __name__ == "__main__":
rst = asyncio.run(hello())
print(rst)
|># python3 main.py
enter hello ...
return world ...
来看下造的轮子的使用方式:
▶ more main.py
from wilsonasyncio import run
async def hello():
print('enter hello ...')
return 'return world ...'
if __name__ == "__main__":
ret = run(hello())
print(ret)
▶ python3 main.py
enter hello ...
return world ...
自己造的轮子也很好的运行了,下面我们来看下轮子的代码
四、代码解析
轮子代码
1)代码组成
|># tree
.
├── eventloops.py
├── futures.py
├── main.py
├── tasks.py
├── wilsonasyncio.py
文件 | 作用 |
eventloops.py | 事件循环 |
futures.py | futures对象 |
tasks.py | tasks对象 |
wilsonasyncio.py | 可调用方法集合 |
main.py | 入口 |
2)代码概览:
eventloops.py
类/函数 | 方法 | 对象 | 作用 | 描述 |
Eventloop | 事件循环,一个线程只有运行一个 | |||
| 初始化两个重要对象 | |||
| 所有的待执行任务都是从这个队列取出来,非常重要 | |||
| 事件循环完成的标志 | |||
| 调用该方法会立即将任务添加到待执行队列 | |||
| 被 | |||
| 死循环,若 | |||
| 非常重要的函数,任务的起点和终点(后面详细介绍) | |||
| 将传入的函数封装成 | |||
| 所有的任务进入待执行队列( | |||
| 初始化两个重要对象 | |||
| 待执行函数主体 | |||
| 待执行函数参数 | |||
| 待执行函数执行 | |||
| 获取当前线程的事件循环 | |||
| 将事件循环的 | |||
| 入口函数 | 新增 |
tasks.py
类/函数 | 方法 | 对象 | 作用 | 描述 |
Task | 继承自Future,主要用于整个协程运行的周期 | |||
| 初始化对象 | |||
| 用户定义的函数主体 | |||
| Task类的核心函数 | |||
| 如果对象是一个Future对象,就返回,否则就会调用 | 新增 |
futures.py
类/函数 | 方法 | 对象 | 作用 | 描述 |
Future | 主要负责与用户函数进行交互 | |||
| 初始化两个重要对象 | |||
| 事件循环 | |||
| 回调队列,任务暂存队列,等待时机成熟(状态不是 | |||
| 添加任务回调函数,状态 | |||
| 获取任务执行结果并存储至 | |||
| 将回调函数放入 | |||
| 获取返回值 |
3)执行过程
3.1)入口函数
main.py
async def hello():
print('enter hello ...')
return 'return world ...'
if __name__ == "__main__":
ret = run(hello())
print(ret)
-
ret = run(hello())
直接调用 run
,参数是用户函数 hello()
,我们看下run的源码
def run(main):
loop = get_event_loop()
return loop.run_until_complete(main)
-
loop = get_event_loop()
获取事件循环 -
return loop.run_until_complete(main)
调用 run_until_complete
3.2)事件循环启动
def run_until_complete(self, future):
future = tasks.ensure_future(future, loop=self)
future.add_done_callback(_complete_eventloop, future)
self.run_forever()
return future.result()
- 与之前略有不同,
future = tasks.ensure_future(future, loop=self)
,调用了 tasks.ensure_future
def ensure_future(coro_or_future, *, loop=None):
if isinstance(coro_or_future, Future):
return coro_or_future
else:
return loop.create_task(coro_or_future)
- 如果传入的对象是一个普通函数,那就封装成一个task;如果已经是一个future对象,那就直接返回。这一步的目的主要是确保传入的对象,是一个Future类型
剩下的部分已经没有什么新鲜的了,和 run_until_complete
一样,我们直接跳过...
3.7)执行结果
▶ python3 main.py
enter hello ...
return world ...
五、流程总结
六、小结
● run
与 run_until_complete
大同小异,只不过入口函数做了一些调整,使得用户调用更加的便利