前言
書接上文,本文造第二個輪子,也是asyncio包裡面非常常用的一個函式run
一、知識準備
● 相對於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 | 事件迴圈,一個執行緒只有執行一個 | |||
__init__ |
初始化兩個重要物件 self._ready 與 self._stopping |
|||
self._ready |
所有的待執行任務都是從這個佇列取出來,非常重要 | |||
self._stopping |
事件迴圈完成的標誌 | |||
call_soon |
呼叫該方法會立即將任務新增到待執行佇列 | |||
run_once |
被run_forever 呼叫,從self._ready 佇列裡面取出任務執行 |
|||
run_forever |
死迴圈,若self._stopping 則退出迴圈 |
|||
run_until_complete |
非常重要的函式,任務的起點和終點(後面詳細介紹) | |||
create_task |
將傳入的函式封裝成task 物件,這個操作會將task.__step 新增到__ready 佇列 |
|||
Handle |
所有的任務進入待執行佇列(Eventloop.call_soon )之前都會封裝成Handle物件 |
|||
__init__ |
初始化兩個重要物件 self._callback 與 self._args |
|||
self._callback |
待執行函式主體 | |||
self._args |
待執行函式引數 | |||
_run |
待執行函式執行 | |||
get_event_loop |
獲取當前執行緒的事件迴圈 | |||
_complete_eventloop |
將事件迴圈的_stopping 標誌置位True |
|||
run |
入口函式 | 新增 |
tasks.py
類/函式 | 方法 | 物件 | 作用 | 描述 |
---|---|---|---|---|
Task | 繼承自Future,主要用於整個協程執行的週期 | |||
__init__ |
初始化物件 self._coro ,並且call_soon 將self.__step 加入self._ready 佇列 |
|||
self._coro |
使用者定義的函式主體 | |||
__step |
Task類的核心函式 | |||
ensure_future |
如果物件是一個Future物件,就返回,否則就會呼叫create_task 返回,並且加入到_ready 佇列 |
新增 |
futures.py
類/函式 | 方法 | 物件 | 作用 | 描述 |
---|---|---|---|---|
Future | 主要負責與使用者函式進行互動 | |||
__init__ |
初始化兩個重要物件 self._loop 與 self._callbacks |
|||
self._loop |
事件迴圈 | |||
self._callbacks |
回撥佇列,任務暫存佇列,等待時機成熟(狀態不是PENDING ),就會進入_ready 佇列 |
|||
add_done_callback |
新增任務回撥函式,狀態_PENDING ,就虎進入_callbacks 佇列,否則進入_ready 佇列 |
|||
set_result |
獲取任務執行結果並儲存至_result ,將狀態置位_FINISH ,呼叫__schedule_callbacks |
|||
__schedule_callbacks |
將回撥函式放入_ready ,等待執行 |
|||
result |
獲取返回值 |
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
大同小異,只不過入口函式做了一些調整,使得使用者呼叫更加的便利
● 本文中的程式碼,參考了python 3.7.7中asyncio的原始碼,裁剪而來
● 本文中程式碼:程式碼
至此,本文結束
在下才疏學淺,有撒湯漏水的,請各位不吝賜教...
更多文章,請關注我:wilson.chai