亚洲熟女综合色一区二区三区,亚洲精品中文字幕无码蜜桃,亚洲va欧美va日韩va成人网,亚洲av无码国产一区二区三区,亚洲精品无码久久久久久久

Python 的異步 IO:Asyncio 簡介

Python 的 asyncio 類似于 C++ 的 Boost.Asio。

異步 IO,就是你發(fā)起一個 IO 操作,不用等它結(jié)束,可以繼續(xù)做其他事情,當(dāng)它結(jié)束時,你會得到通知。

Asyncio 是并發(fā)(concurrency)的一種方式。對 Python 來說,并發(fā)還可以通過線程(threading)和多進(jìn)程(multiprocessing)來實(shí)現(xiàn)。

Asyncio 并不能帶來真正的并行(parallelism)。當(dāng)然,因?yàn)?GIL(全局解釋器鎖)的存在,Python 的多線程也不能帶來真正的并行。

可交給 asyncio 執(zhí)行的任務(wù),稱為協(xié)程(coroutine)。一個協(xié)程可以放棄執(zhí)行,把機(jī)會讓給其它協(xié)程(即 yield from 或 await)。

Python 的異步 IO:Asyncio 簡介

定義協(xié)程

協(xié)程的定義,需要使用 async def 語句。

Python 的異步 IO:Asyncio 簡介

do_some_work 便是一個協(xié)程。

準(zhǔn)確來說,do_some_work 是一個協(xié)程函數(shù),可以通過 asyncio.iscoroutinefunction 來驗(yàn)證:

Python 的異步 IO:Asyncio 簡介

這個協(xié)程什么都沒做,我們讓它睡眠幾秒,以模擬實(shí)際的工作量 :

Python 的異步 IO:Asyncio 簡介

在解釋 await 之前,有必要說明一下協(xié)程可以做哪些事。協(xié)程可以:

Python 的異步 IO:Asyncio 簡介

asyncio.sleep 也是一個協(xié)程,所以 await asyncio.sleep(x) 就是等待另一個協(xié)程??蓞⒁?asyncio.sleep 的文檔:

Python 的異步 IO:Asyncio 簡介

Python 的異步 IO:Asyncio 簡介

運(yùn)行協(xié)程

調(diào)用協(xié)程函數(shù),協(xié)程并不會開始運(yùn)行,只是返回一個協(xié)程對象,可以通過 asyncio.iscoroutine 來驗(yàn)證:

Python 的異步 IO:Asyncio 簡介

此處還會引發(fā)一條警告:

Python 的異步 IO:Asyncio 簡介

要讓這個協(xié)程對象運(yùn)行的話,有兩種方式:

Python 的異步 IO:Asyncio 簡介

簡單來說,只有 loop 運(yùn)行了,協(xié)程才可能運(yùn)行。

下面先拿到當(dāng)前線程缺省的 loop ,然后把協(xié)程對象交給 loop.run_until_complete,協(xié)程對象隨后會在 loop 里得到運(yùn)行。

Python 的異步 IO:Asyncio 簡介

run_until_complete 是一個阻塞(blocking)調(diào)用,直到協(xié)程運(yùn)行結(jié)束,它才返回。這一點(diǎn)從函數(shù)名不難看出。

run_until_complete 的參數(shù)是一個 future,但是我們這里傳給它的卻是協(xié)程對象,之所以能這樣,是因?yàn)樗趦?nèi)部做了檢查,通過 ensure_future 函數(shù)把協(xié)程對象包裝(wrap)成了 future。所以,我們可以寫得更明顯一些:

Python 的異步 IO:Asyncio 簡介

完整代碼:

Python 的異步 IO:Asyncio 簡介

運(yùn)行結(jié)果:

Python 的異步 IO:Asyncio 簡介

Python 的異步 IO:Asyncio 簡介

回調(diào)

假如協(xié)程是一個 IO 的讀操作,等它讀完數(shù)據(jù)后,我們希望得到通知,以便下一步數(shù)據(jù)的處理。這一需求可以通過往 future 添加回調(diào)來實(shí)現(xiàn)。

Python 的異步 IO:Asyncio 簡介

Python 的異步 IO:Asyncio 簡介

多個協(xié)程

實(shí)際項(xiàng)目中,往往有多個協(xié)程,同時在一個 loop 里運(yùn)行。為了把多個協(xié)程交給 loop,需要借助 asyncio.gather 函數(shù)。

Python 的異步 IO:Asyncio 簡介

或者先把協(xié)程存在列表里:

Python 的異步 IO:Asyncio 簡介

運(yùn)行結(jié)果:

Python 的異步 IO:Asyncio 簡介

這兩個協(xié)程是并發(fā)運(yùn)行的,所以等待的時間不是 1 + 3 = 4 秒,而是以耗時較長的那個協(xié)程為準(zhǔn)。

參考函數(shù) gather 的文檔:

Python 的異步 IO:Asyncio 簡介

發(fā)現(xiàn)也可以傳 futures 給它:

Python 的異步 IO:Asyncio 簡介

gather 起聚合的作用,把多個 futures 包裝成單個 future,因?yàn)?loop.run_until_complete 只接受單個 future。

Python 的異步 IO:Asyncio 簡介

run_until_complete 和 run_forever

我們一直通過 run_until_complete 來運(yùn)行 loop ,等到 future 完成,run_until_complete 也就返回了。

Python 的異步 IO:Asyncio 簡介

輸出:

Python 的異步 IO:Asyncio 簡介

現(xiàn)在改用 run_forever:

Python 的異步 IO:Asyncio 簡介

輸出:

Python 的異步 IO:Asyncio 簡介

三秒鐘過后,future 結(jié)束,但是程序并不會退出。run_forever 會一直運(yùn)行,直到 stop 被調(diào)用,但是你不能像下面這樣調(diào) stop:

Python 的異步 IO:Asyncio 簡介

run_forever 不返回,stop 永遠(yuǎn)也不會被調(diào)用。所以,只能在協(xié)程中調(diào) stop:

Python 的異步 IO:Asyncio 簡介

這樣并非沒有問題,假如有多個協(xié)程在 loop 里運(yùn)行:

Python 的異步 IO:Asyncio 簡介

第二個協(xié)程沒結(jié)束,loop 就停止了——被先結(jié)束的那個協(xié)程給停掉的。

要解決這個問題,可以用 gather 把多個協(xié)程合并成一個 future,并添加回調(diào),然后在回調(diào)里再去停止 loop。

Python 的異步 IO:Asyncio 簡介

其實(shí)這基本上就是 run_until_complete 的實(shí)現(xiàn)了,run_until_complete 在內(nèi)部也是調(diào)用 run_forever。

Python 的異步 IO:Asyncio 簡介

Close Loop?

以上示例都沒有調(diào)用 loop.close,好像也沒有什么問題。所以到底要不要調(diào) loop.close 呢?

簡單來說,loop 只要不關(guān)閉,就還可以再運(yùn)行。:

Python 的異步 IO:Asyncio 簡介

但是如果關(guān)閉了,就不能再運(yùn)行了:

Python 的異步 IO:Asyncio 簡介

建議調(diào)用 loop.close,以徹底清理 loop 對象防止誤用。

Python 的異步 IO:Asyncio 簡介

gather vs. wait

asyncio.gather 和 asyncio.wait 功能相似。

Python 的異步 IO:Asyncio 簡介

具體差別可請參見 StackOverflow 的討論:Asyncio.gather vs asyncio.wait。

Python 的異步 IO:Asyncio 簡介

Timer

C++ Boost.Asio 提供了 IO 對象 timer,但是 Python 并沒有原生支持 timer,不過可以用 asyncio.sleep 模擬。

Python 的異步 IO:Asyncio 簡介

相關(guān)新聞

歷經(jīng)多年發(fā)展,已成為國內(nèi)好評如潮的Linux云計算運(yùn)維、SRE、Devops、網(wǎng)絡(luò)安全、云原生、Go、Python開發(fā)專業(yè)人才培訓(xùn)機(jī)構(gòu)!