0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Python異步IO的核心知識(shí),你掌握了嗎?

馬哥Linux運(yùn)維 ? 來(lái)源:lq ? 2018-12-04 17:09 ? 次閱讀

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

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

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

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

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

定義協(xié)程

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

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

準(zhǔn)確來(lái)說(shuō),do_some_work 是一個(gè)協(xié)程函數(shù),可以通過(guò) asyncio.iscoroutinefunction 來(lái)驗(yàn)證:

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

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

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

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

調(diào)用協(xié)程函數(shù),協(xié)程并不會(huì)開(kāi)始運(yùn)行,只是返回一個(gè)協(xié)程對(duì)象,可以通過(guò) asyncio.iscoroutine 來(lái)驗(yàn)證:

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

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

簡(jiǎn)單來(lái)說(shuō),只有 loop 運(yùn)行了,協(xié)程才可能運(yùn)行。

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

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

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

完整代碼:

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

回調(diào)

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

多個(gè)協(xié)程

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

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

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

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

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

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

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

run_until_complete 和 run_forever

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

輸出:

現(xiàn)在改用 run_forever:

輸出:

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

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

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

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

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

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

Close Loop?

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

簡(jiǎn)單來(lái)說(shuō),loop 只要不關(guān)閉,就還可以再運(yùn)行。:

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

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

gather vs. wait

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

具體差別可請(qǐng)參見(jiàn) StackOverflow 的討論:Asyncio.gather vs asyncio.wait。

Timer

C++ Boost.Asio 提供了 IO 對(duì)象 timer,但是 Python 并沒(méi)有原生支持 timer,不過(guò)可以用 asyncio.sleep 模擬。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • python
    +關(guān)注

    關(guān)注

    53

    文章

    4753

    瀏覽量

    84078
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    501

    瀏覽量

    19580

原文標(biāo)題:Python 的異步 IO:Asyncio 簡(jiǎn)介

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linux驅(qū)動(dòng)學(xué)習(xí)筆記:異步IO

    前幾篇介紹了幾種IO模型,今天介紹另一種IO模型——異步IO
    發(fā)表于 06-12 16:24 ?594次閱讀

    [8.1]--C++核心知識(shí),掌握了嗎?

    人工智能
    jf_90840116
    發(fā)布于 :2023年02月20日 22:11:34

    異步IO是什么

    python 異步ioAsync IO is a concurrent programming design that has received dedicated support
    發(fā)表于 09-06 07:26

    數(shù)據(jù)結(jié)構(gòu)預(yù)算法核心知識(shí)點(diǎn)總結(jié)概述

    數(shù)據(jù)結(jié)構(gòu)預(yù)算法核心知識(shí)點(diǎn)總結(jié)概述最近有看一些大佬的專欄,受益匪淺。深刻的覺(jué)察到我們要想成為一個(gè)偉大的程序員,或者說(shuō)小一點(diǎn),成為一個(gè)厲害的程序員,基礎(chǔ)知識(shí)核心競(jìng)爭(zhēng)力也是我們不斷向上提升個(gè)人能力的基石
    發(fā)表于 12-21 08:00

    嵌入式開(kāi)發(fā)中會(huì)用到哪些核心知識(shí)

    、什么是嵌入式、嵌入式系統(tǒng)的技術(shù)特征、三次信息化浪潮、嵌入式技術(shù)的主要發(fā)展方向和主流產(chǎn)品。2、什么人適合學(xué)習(xí)嵌入式本節(jié)主要講述嵌入式開(kāi)發(fā)中會(huì)用到哪些核心知識(shí),需要哪些核心技能,嵌入式開(kāi)發(fā)和Android應(yīng)用、微信定制開(kāi)發(fā)等純應(yīng)用層開(kāi)發(fā)的不同之處,最后分析了哪些人適合學(xué)習(xí)嵌
    發(fā)表于 12-24 07:39

    IIC的核心知識(shí)點(diǎn)匯總,絕對(duì)實(shí)用

    IIC的核心知識(shí)點(diǎn)匯總,絕對(duì)實(shí)用
    發(fā)表于 01-24 06:14

    FPGA核心知識(shí)詳解(1):FPGA入門(mén)必備

    電子發(fā)燒友網(wǎng)核心提示 :對(duì)初級(jí)FPGA工程師而言,必須掌握FPGA相關(guān)基礎(chǔ)知識(shí)、精通硬件描述語(yǔ)言、熟練數(shù)字電路設(shè)計(jì)、加強(qiáng)工程項(xiàng)目的實(shí)踐。應(yīng)廣大初級(jí)FPGA工程師/FPGA愛(ài)好者之需,電子
    發(fā)表于 11-09 13:55 ?7992次閱讀

    縱觀全球頂級(jí)新材料實(shí)驗(yàn)室,知識(shí)點(diǎn)都抓住了嗎?

    縱觀全球頂級(jí)新材料實(shí)驗(yàn)室,知識(shí)點(diǎn)都抓住了嗎?
    的頭像 發(fā)表于 04-22 17:36 ?2952次閱讀
    縱觀全球頂級(jí)新材料實(shí)驗(yàn)室,<b class='flag-5'>知識(shí)</b>點(diǎn)<b class='flag-5'>你</b>都抓住<b class='flag-5'>了嗎</b>?

    曾經(jīng)分不清的RAM知識(shí) 現(xiàn)在搞明白了嗎

    曾經(jīng)分不清的RAM知識(shí),現(xiàn)在搞明白了嗎
    的頭像 發(fā)表于 02-25 15:33 ?3043次閱讀

    淺析同步與異步Python的區(qū)別與概述

    是否聽(tīng)到人們說(shuō)過(guò),異步Python代碼比普通(或同步)Python代碼更快?果真是那樣嗎?
    的頭像 發(fā)表于 04-25 13:53 ?2126次閱讀
    淺析同步與<b class='flag-5'>異步</b><b class='flag-5'>Python</b>的區(qū)別與概述

    信號(hào)驅(qū)動(dòng)IO異步IO的區(qū)別

    一. 談信號(hào)驅(qū)動(dòng)IO (對(duì)比異步IO來(lái)看) 信號(hào)驅(qū)動(dòng)IO 對(duì)比 異步 IO進(jìn)行理解 信號(hào)驅(qū)動(dòng)
    的頭像 發(fā)表于 11-08 15:32 ?811次閱讀
    信號(hào)驅(qū)動(dòng)<b class='flag-5'>IO</b>與<b class='flag-5'>異步</b><b class='flag-5'>IO</b>的區(qū)別

    linux異步io框架iouring應(yīng)用

    Linux內(nèi)核5.1支持了新的異步IO框架iouring,由Block IO大神也即Fio作者Jens Axboe開(kāi)發(fā),意在提供一套公用的網(wǎng)絡(luò)和磁盤(pán)異步
    的頭像 發(fā)表于 11-08 15:39 ?498次閱讀
    linux<b class='flag-5'>異步</b><b class='flag-5'>io</b>框架iouring應(yīng)用

    異步IO框架iouring介紹

    前言 Linux內(nèi)核5.1支持了新的異步IO框架iouring,由Block IO大神也即Fio作者Jens Axboe開(kāi)發(fā),意在提供一套公用的網(wǎng)絡(luò)和磁盤(pán)異步
    的頭像 發(fā)表于 11-09 09:30 ?1667次閱讀
    <b class='flag-5'>異步</b><b class='flag-5'>IO</b>框架iouring介紹

    電源時(shí)序控制的正確方法,掌握了嗎?

    電源時(shí)序控制的正確方法,掌握了嗎?
    的頭像 發(fā)表于 12-15 09:27 ?1098次閱讀
    電源時(shí)序控制的正確方法,<b class='flag-5'>你</b><b class='flag-5'>掌握</b><b class='flag-5'>了嗎</b>?

    淺談初級(jí)電工必備知識(shí)點(diǎn)

    對(duì)于初學(xué)電工的朋友來(lái)說(shuō),掌握一些基礎(chǔ)且實(shí)用的知識(shí)點(diǎn)是非常重要的。本文旨在分享初級(jí)電工應(yīng)該掌握核心知識(shí),幫助新手電工更好地入門(mén)和提升技能。
    的頭像 發(fā)表于 12-26 10:44 ?865次閱讀