Python異步編程介紹

An introduction to asynchronous Python原文

作者: Jake Edge 于2017年6月28日

在他的PyCon 2017演講中,Miguel Grinberg希望通過Python來介紹異步編程給完全的初學者。 有很多關于異步Python的討論,特別是隨著asyncio模塊的出現(xiàn) 。但是有多種方法可以創(chuàng)建異步Python程序,其中許多方法已經可用了很長時間。 在演講中,Grinberg從這些解決方案的復雜性中退了一步,從更高層次來看異步處理方式。

他開始談到,盡管他在基于Python的Flask 網(wǎng)頁微型框架上做了大量的工作,這個演講不會是關于Flask的。他寫的是Flask Mega-Tutorial (一本關于Flask的書 ),但是在演講中他會提到不到十次,這是他令人羨慕的壯舉。他還開發(fā)了一個用于Socket.IO的Python服務器 ,它開始于前面說的 “框架”,但沒料到它 “自己的生活” 已經開始了。

Miguel Grinberg

他詢問參加者是否聽到有人說 “異步會使你的代碼更快速” 。如果是這樣,他說,他的演講會解釋為什么人們這么說。 他開始簡單地定義 “異步(async)” (因為 “asynchronous” 通常被縮短)。 它是并行編程的一種方法,這意味著一次執(zhí)行很多操作。他在這里提到的不僅僅是asyncio ,因為有許多方法可以讓Python一次性執(zhí)行多個操作。

然后他回顧了這些機制。首先是多個進程,其中操作系統(tǒng)(OS)執(zhí)行多任務的所有工作。 在CPython(參考Python實現(xiàn))中,這是使用系統(tǒng)中所有核的唯一方法。 另一種同時做多個事情的方式是使用多線程,這也是操作系統(tǒng)處理多任務的一種方式,但Python的全局解釋器鎖(Global Interpreter Lock,GIL)會阻止多核并發(fā)。另一方面,異步編程不需要OS參與。 只有有一個進程和線程,但該程序可以一次完成多項操作。 他問: “訣竅是什么?”

象棋

他轉向了一個現(xiàn)實世界的例子:一個象棋大師在象棋展,同時面對24個對手。 “在電腦殺死象棋之前,這些展覽定期進行,但他不確定是否現(xiàn)今還在。” 如果每個游戲需要大約30個成對移動來完成,如果連續(xù)玩(每個成對移動一分鐘),大師將需要12小時才能完成比賽。 但是,通過在每個游戲中依次進行動作,整個練習可以在一個小時內完成。 大師只是在一個棋盤上(在五秒鐘內)移動,然后繼續(xù)下一步,在大師返回之前(進行另外23個動作)后,讓對手有很多時間移動。 格林伯格說,那位大師在那個時候會 “讓大家玩好” 。

人們正在談論的異步編程就是 “這樣的快速” 。象棋大師沒有優(yōu)化玩的更快,只是工作安排得好,使他們不浪費時間做無謂的等待。 他說: “這是異步編程的完整秘密” ,他說: “這就是怎么運作的”。 在這種情況下,CPU就是象棋大師,它等待盡可能少的時間。

但與會者可能想知道如何只使用一個進程和一個線程來完成。 如何實現(xiàn)異步? 需要的一件事是,一種方法可以來暫停和恢復執(zhí)行函數(shù)。他們將在等待時掛起(suspend)且在等待結束時恢復(resume)。 這聽起來很難做,但在Python中有四種方法可以在不涉及操作系統(tǒng)的情況下進行。

他的第一個方法是回調函數(shù),這是 “顯而易見(gross)” ,他說。 如此顯而易見,事實上,他甚至沒有舉個例子。 另一個是使用生成器函數(shù) ,這是Python長期以來的一部分。最近的Python從3.5開始,具有async和await關鍵字 ,可以用于異步程序。 還有一個第三方軟件包, greenlet ,它有一個Python的C擴展,以支持掛起和恢復。

還需要有一件事情以支持異步編程:調度器,可以跟蹤掛起的函數(shù),并在正確的時間恢復它們。在異步世界中,該調度程序被稱為 “事件循環(huán)” 。 當函數(shù)暫停時,它將控制權返回給事件循環(huán),該循環(huán)找到另一個需要啟動或恢復的函數(shù)。 這不是一個新的想法; 它與Windows和macOS的舊版本中使用的 “合作多任務” 實際上是一樣的。

例子

Grinberg創(chuàng)建了一個使用一些不同機制的簡單 “hello world” 程序的例子 。 他在演講中并沒有講到他們的全部,也鼓勵觀眾看其余的部分。 他開始于一個簡單的同步示例,它具有在打印 “Hello” 和 “World!” 之間睡三秒鐘的功能。 如果他在一個循環(huán)中調用了十次,則需要30秒才能完成,因為每個函數(shù)都將背靠背運行。

然后他使用asyncio顯示了兩個例子。它們本質上是一樣的,但是一個使用@coroutine裝飾器(decorator)給函數(shù)且在函數(shù)體內使用yield from(生成器函數(shù)的風格),而另一個使用async def的函數(shù),并在函數(shù)體中await。 兩者都使用asyncio版本的sleep()函數(shù)在兩次print()調用之間休眠三秒鐘。 除了這些差異,還有一些樣板設置事件循環(huán)并從中調用函數(shù),這兩個函數(shù)具有與原始示例相同的核心代碼。非樣板差異是有意設計的; asyncio使代碼掛起和恢復的地方 “非常明確” 。

這兩個程序如下所示:

    # async/await version
    
    import asyncio
    loop = asyncio.get_event_loop()

    async def hello():
        print('Hello')
        await asyncio.sleep(3)
        print('World!')

    if __name__ == '__main__':
        loop.run_until_complete(hello())
    # @coroutine decorator version

    import asyncio
    loop = asyncio.get_event_loop()

    @asyncio.coroutine
    def hello():
        print('Hello')
        yield from asyncio.sleep(3)
        print('World!')

    if __name__ == '__main__':
        loop.run_until_complete(hello())

運行程序給出了預期的結果(兩個字符串之間的三秒鐘),但是如果你在循環(huán)中包裝函數(shù)調用,它會變得更有趣。 如果循環(huán)十次迭代,結果將是十個 “Hello” 字符串,三秒鐘等待,然后十個 “World!” 字符串。

另外還有一些asyncio以外的示例,包括greenlet和Twisted。greenlet示例看起來與同步示例幾乎完全相同,只是使用不同的sleep() 。 那就是因為greenlet試圖使異步編程變得透明,但是隱藏這些差異可能是一個祝福也可能是詛咒,Grinberg說。

陷阱

在異步編程中有一些陷阱,人們總是會栽在這些事情上。如果有一個任務要求CPU使用量大,那么在進行計算時就不會做任何事情了。 為了讓其他事情發(fā)生,計算需要定期釋放CPU。這可以通過睡眠0秒來完成,例如(使用等待asyncio.sleep(0))。

然而,許多Python標準庫以阻塞方式編寫,因此套接字, 子進程和線程模塊(以及使用它們的其他模塊)以及諸如time.sleep()之類的簡單內容不能在異步程序中使用。 Grinberg說,所有的異步框架都為這些模塊提供了自己的非阻塞替換,但這意味著 “你必須重新學習如何做這些你已經知道如何做的事情” 。

Eventlet和gevent,它們都是基于greenlet的,它們都可以用來修補標準庫,使其與異步兼容,但這不是asyncio的功能。 它是一個不試圖隱藏程序異步性質的框架。asyncio希望您在設計和編寫代碼時考慮異步編程。

對照

他結束他的演講,比較了不同類別的進程,線程和異步。 所有這些技術都優(yōu)化了等待期; 進程和線程讓操作系統(tǒng)為他們做,而異步程序和框架為自己做。只有進程可以使用系統(tǒng)的所有內核,但線程和異步程序不能使用。 這導致一些人編寫程序,將每個核心的一個進程與線程和/或異步功能相結合,這可以很好地工作,他說。

可擴展性是 “有趣的” 。 運行多個進程意味著有多個Python副本,應用程序和所有在內存中使用的資源,所以在相當少的同時進程(數(shù)十個進程是可能的限制)后,系統(tǒng)將耗盡內存,Grinberg說。線程更輕巧,所以可以有更多的,甚至數(shù)百個。但異步程序是 “非常輕量級的” ,可以處理成千上萬個同時執(zhí)行的任務。

阻塞標準庫函數(shù)可以從進程和線程使用,但不能用于異步程序。GIL只會干擾線程,進程和異步可以和它共存就可以了。 不過,他指出,即使對于他經驗中的線程,GIL只有 “一些” 干擾; 當線程在I/O上被阻塞時,它們將不會保持GIL,所以操作系統(tǒng)將給予另一個線程CPU。

在這種比較中,沒有幾個能比async好。Grinberg說,Python的異步程序的主要優(yōu)點是它們允許的大規(guī)模擴展。 因此,如果您的服務器將處于超級忙碌狀態(tài)并處理大量同時發(fā)生的客戶端,則async可能會幫助您避免購買服務器而破產。 異步編程模型也可能由于其他原因而有吸引力,這是完全有效的,但嚴格按照處理優(yōu)勢,表明可縮放(scaling)是async真正獲勝的地方。

有關Grinberg的演講的YouTube視頻是可用的; 演講者甲板幻燈片(Speaker Deck slides)是相似的,但不同于他所使用的版本。

[我要感謝Linux基金會為去波特蘭參加PyCon提供的旅行援助。]

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容