精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

談?wù)凱ython協(xié)程技術(shù)的演進(jìn)

開發(fā) 開發(fā)工具 后端
作為程序員,在一門語(yǔ)言上深入同樣可以帶來(lái)知識(shí)的廣度。不同語(yǔ)言有不同的性格,合適的工具解決合適的問題。

一、引言

1. 存儲(chǔ)器山

存儲(chǔ)器山是 Randal Bryant 在《深入理解計(jì)算機(jī)系統(tǒng)》一書中提出的概念。

基于成本、效率的考量,計(jì)算機(jī)存儲(chǔ)器被設(shè)計(jì)成多級(jí)金字塔結(jié)構(gòu),塔頂是速度最快、成本***的 CPU 內(nèi)部的寄存器(一般幾 KB)與高速緩存,塔底是成本***、速度最慢的廣域網(wǎng)云存儲(chǔ)(如百度云免費(fèi) 2T )

存儲(chǔ)器山的指導(dǎo)意義在于揭示了良好設(shè)計(jì)程序的必要條件是需要有優(yōu)秀的局部性:

  • 時(shí)間局部性:相同時(shí)間內(nèi),訪問同一地址次數(shù)越多,則時(shí)間局部性表現(xiàn)越佳;
  • 空間局部性:下一次訪問的存儲(chǔ)器地址與上一次的訪問過(guò)的存儲(chǔ)器地址位置鄰近;

2. cpu的時(shí)間觀

cpu的時(shí)間觀

我們將一個(gè)普通的 2.6GHz 的 CPU 的延遲時(shí)間放大到人能體驗(yàn)的尺度上(數(shù)據(jù)來(lái)自微信公眾號(hào) 駒說(shuō)碼事):在存儲(chǔ)器頂層執(zhí)行單條寄存器指令的時(shí)間為1秒鐘;從第五層磁盤讀 1MB 數(shù)據(jù)卻需要一年半;ping 不同的城域網(wǎng)主機(jī),網(wǎng)絡(luò)包需要走 12.5 年。

如果程序發(fā)送了一個(gè) HTTP 包后便阻塞在同步等待響應(yīng)的過(guò)程上,計(jì)算機(jī)不得不傻等 12 年后的那個(gè)響應(yīng)再處理別的事情,低下的硬件利用率必然導(dǎo)致低下的程序效率。

3. 同步編程

從以上數(shù)據(jù)可以看出,內(nèi)存數(shù)據(jù)讀寫、磁盤尋道讀寫、網(wǎng)卡讀寫等操作都是 I/O 操作,同步程序的瓶頸在于漫長(zhǎng)的 I/O 等待,想要提高程序效率必須減少 I/O 等待時(shí)間,從提高程序的局部性著手。

同步編程的改進(jìn)方式有多進(jìn)程、多線程,但對(duì)于 c10k 問題都不是良好的解決方案,多進(jìn)程的方式存在操作系統(tǒng)可調(diào)度進(jìn)程數(shù)量上限較低,進(jìn)程間上下文切換時(shí)間過(guò)長(zhǎng),進(jìn)程間通信較為復(fù)雜。

而 Python 的多線程方式,由于存在眾所周知的 GIL 鎖,性能提升并不穩(wěn)定,僅能滿足成百上千規(guī)模的 I/O 密集型任務(wù),多線程還有一個(gè)缺點(diǎn)是由操作系統(tǒng)進(jìn)行搶占式調(diào)度存在競(jìng)態(tài)條件,可能需要引入了鎖與隊(duì)列等保障原子性操作的工具。

4. 異步編程

說(shuō)到異步非阻塞調(diào)用,目前的代名詞都是 epoll 與 kqueue,select/poll 由于效率問題基本已被取代。

epoll 是04年 Linux2.6 引入內(nèi)核的一種 I/O 事件通知機(jī)制,它的作用是將大量的文件描述符托管給內(nèi)核,內(nèi)核將***層的 I/O 狀態(tài)變化封裝成讀寫事件,這樣就避免了由程序員去主動(dòng)輪詢狀態(tài)變化的重復(fù)工作,程序員將回調(diào)函數(shù)注冊(cè)到 epoll 的狀態(tài)上,當(dāng)檢測(cè)到相對(duì)應(yīng)文件描述符產(chǎn)生狀態(tài)變化時(shí),就進(jìn)行函數(shù)回調(diào)。

事件循環(huán)是異步編程的底層基石。

簡(jiǎn)單的EventLoop的實(shí)現(xiàn)原理

上圖是簡(jiǎn)單的EventLoop的實(shí)現(xiàn)原理,

  • 用戶創(chuàng)建了兩個(gè)socket連接,將系統(tǒng)返回的兩個(gè)文件描述符fd3、fd4通過(guò)系統(tǒng)調(diào)用在epoll上注冊(cè)讀寫事件;
  • 當(dāng)網(wǎng)卡解析到一個(gè)tcp包時(shí),內(nèi)核根據(jù)五元組找到相應(yīng)到文件描述符,自動(dòng)觸發(fā)其對(duì)應(yīng)的就緒事件狀態(tài),并將該文件描述符添加到就緒鏈表中。
  • 程序調(diào)用epoll.poll(),返回可讀寫的事件集合。
  • 對(duì)事件集合進(jìn)行輪詢,調(diào)用回調(diào)函數(shù)等
  • 一輪事件循環(huán)結(jié)束,循環(huán)往復(fù)。

epoll 并非銀彈,從圖中可以觀察到,如果用戶關(guān)注的層次很低,直接操作epoll去構(gòu)造維護(hù)事件的循環(huán),從底層到高層的業(yè)務(wù)邏輯需要層層回調(diào),造成callback hell,并且可讀性較差。所以,這個(gè)繁瑣的注冊(cè)回調(diào)與回調(diào)的過(guò)程得以封裝,并抽象成EventLoop。EventLoop屏蔽了進(jìn)行epoll系統(tǒng)調(diào)用的具體操作。對(duì)于用戶來(lái)說(shuō),將不同的I/O狀態(tài)考量為事件的觸發(fā),只需關(guān)注更高層次下不同事件的回調(diào)行為。諸如libev, libevent之類的使用C編寫的高性能異步事件庫(kù)已經(jīng)取代這部分瑣碎的工作。

在Python框架里一般會(huì)見到的這幾種事件循環(huán):

  • libevent/libev: Gevent(greenlet+前期libevent,后期libev)使用的網(wǎng)絡(luò)庫(kù),廣泛應(yīng)用;
  • tornado: tornado框架自己實(shí)現(xiàn)的IOLOOP;
  • picoev: meinheld(greenlet+picoev)使用的網(wǎng)絡(luò)庫(kù),小巧輕量,相較于libevent在數(shù)據(jù)結(jié)構(gòu)和事件檢測(cè)模型上做了改進(jìn),所以速度更快。但從github看起來(lái)已經(jīng)年久失修,用的人不多。
  • uvloop: Python3時(shí)代的新起之秀。Guido操刀打造了asyncio庫(kù),asyncio可以配置可插拔的event loop,但需要滿足相關(guān)的API要求,uvloop繼承自libuv,將一些低層的結(jié)構(gòu)體和函數(shù)用Python對(duì)象包裝。目前Sanic框架基于這個(gè)庫(kù)

5. 協(xié)程

EventLoop簡(jiǎn)化了不同平臺(tái)上的事件處理,但是處理事件觸發(fā)時(shí)的回調(diào)依然很麻煩,響應(yīng)式的異步程序編寫對(duì)程序員的心智是一項(xiàng)不小的麻煩。

因此,協(xié)程被引入來(lái)替代回調(diào)以簡(jiǎn)化問題。協(xié)程模型主要在在以下方面優(yōu)于回調(diào)模型:

  • 以近似同步代碼的編程模式取代異步回調(diào)模式,真實(shí)的業(yè)務(wù)邏輯往往是同步線性推演的,因此,這種同步式的代碼寫起來(lái)更加容易。底層的回調(diào)依然是callback hell,但這部分臟活累活已經(jīng)轉(zhuǎn)交給編譯器與解釋器去完成,程序員不易出錯(cuò)。
  • 異常處理更加健全,可以復(fù)用語(yǔ)言內(nèi)的錯(cuò)誤處理機(jī)制,回調(diào)方式。而傳統(tǒng)異步回調(diào)模式需要自己判定成功失敗,錯(cuò)誤處理行為復(fù)雜化。
  • 上下文管理簡(jiǎn)單化,回調(diào)方式代碼上下文管理嚴(yán)重依賴閉包,不同的回調(diào)函數(shù)之間相互耦合,割裂了相同的上下文處理邏輯。協(xié)程直接利用代碼的執(zhí)行位置來(lái)表示狀態(tài),而回調(diào)則是維護(hù)了一堆數(shù)據(jù)結(jié)構(gòu)來(lái)處理狀態(tài)。
  • 方便處理并發(fā)行為,協(xié)程的開銷成本很低,每一個(gè)協(xié)程僅有一個(gè)輕巧的用戶態(tài)棧空間。

6. EventLoop與協(xié)程的發(fā)展史

04年,event-driven 的 nginx 誕生并快速傳播,06年以后從俄語(yǔ)區(qū)國(guó)家擴(kuò)散到全球。同時(shí)期,EventLoop 變得具象化與多元化,相繼在不同的編程語(yǔ)言實(shí)現(xiàn)。

近十年以來(lái),后端領(lǐng)域內(nèi)古老的子例程與事件循環(huán)得到結(jié)合,協(xié)程(協(xié)作式子例程)快速發(fā)展,并也革新與誕生了一些語(yǔ)言,比如 golang 的 goroutine,luajit 的 coroutine,Python 的 gevent,erlang 的 process,scala 的 actor 等。

就不同語(yǔ)言中面向并發(fā)設(shè)計(jì)的協(xié)程實(shí)現(xiàn)而言,Scala 與 Erlang 的 Actor 模型、Golang 中的 goroutine 都較 Python 更為成熟,不同的協(xié)程使用通信來(lái)共享內(nèi)存,優(yōu)化了競(jìng)態(tài)、沖突、不一致性等問題。然而,根本的理念沒有區(qū)別,都是在用戶態(tài)通過(guò)事件循環(huán)驅(qū)動(dòng)實(shí)現(xiàn)調(diào)度。

由于歷史包袱較少,后端語(yǔ)言上的各種異步技術(shù)除 Python Twisted 外基本也沒有 callback hell 的存在。其他的方案都已經(jīng)將 callback hell 的過(guò)程進(jìn)行封裝,交給庫(kù)代碼、編譯器、解釋器去解決。

有了協(xié)程,有了事件循環(huán)庫(kù),傳統(tǒng)的 C10K 問題已經(jīng)不是挑戰(zhàn)并已經(jīng)上升到了 C1M 問題。

二、Gevent

Python2 時(shí)代的協(xié)程技術(shù)主要是 Gevent,另一個(gè) meinheld 比較小眾。Gevent 有褒有貶,負(fù)面觀點(diǎn)認(rèn)為它的實(shí)現(xiàn)不夠 Pythonic,脫離解釋器獨(dú)自實(shí)現(xiàn)了黑盒的調(diào)度器,monkey patch 讓不了解的用戶產(chǎn)生混淆。正面觀點(diǎn)認(rèn)為正是這樣才得以屏蔽所有的細(xì)節(jié),簡(jiǎn)化使用難度。

Gevent 基于 Greenlet 與 Libev,greenlet 是一種微線程或者協(xié)程,在調(diào)度粒度上比 PY3 的協(xié)程更大。greenlet 存在于線程容器中,其行為類似線程,有自己獨(dú)立的棧空間,不同的 greenlet 的切換類似操作系統(tǒng)層的線程切換。

greenlet.hub 也是一個(gè)繼承于原生 greenlet 的對(duì)象,也是其他 greenlet 的父節(jié)點(diǎn),它主要負(fù)責(zé)任務(wù)調(diào)度。當(dāng)一個(gè) greenlet 協(xié)程執(zhí)行完部分例程后到達(dá)斷點(diǎn),通過(guò) greenlet.switch() 向上轉(zhuǎn)交控制權(quán)給 hub 對(duì)象,hub 執(zhí)行上下文切換的操作:從寄存器、高速緩存中備份當(dāng)前 greenlet 的棧內(nèi)容到內(nèi)存中,并將原來(lái)備份的另一個(gè) greenlet 棧數(shù)據(jù)恢復(fù)到寄存器中。

hub 對(duì)象內(nèi)封裝了一個(gè) loop 對(duì)象,loop 負(fù)責(zé)封裝 libev 的相關(guān)操作并向上提供接口,所有 greenlet 在通過(guò) loop 驅(qū)動(dòng)的 hub 下被調(diào)度。

三、從yield到async/await

1. 生成器的進(jìn)化

在 Python2.2 中,***次引入了生成器,生成器實(shí)現(xiàn)了一種惰性、多次取值的方法,此時(shí)還是通過(guò) next 構(gòu)造生成迭代鏈或 next 進(jìn)行多次取值。

直到在 Python2.5 中,yield 關(guān)鍵字被加入到語(yǔ)法中,這時(shí),生成器有了記憶功能,下一次從生成器中取值可以恢復(fù)到生成器上次 yield 執(zhí)行的位置。

之前的生成器都是關(guān)于如何構(gòu)造迭代器,在 Python2.5 中生成器還加入了 send 方法,與 yield 搭配使用。

我們發(fā)現(xiàn),此時(shí),生成器不僅僅可以 yield 暫停到一個(gè)狀態(tài),還可以往它停止的位置通過(guò) send 方法傳入一個(gè)值改變其狀態(tài)。

舉一個(gè)簡(jiǎn)單的示例,主要熟悉 yield 與 send 與外界的交互流程:

  1. def jump_range(up_to): 
  2.     step = 0 
  3.     while step < up_to: 
  4.       jump = yield step 
  5.       print("jump", jump) 
  6.       if jump is None: 
  7.           jump = 1 
  8.           step += jump 
  9.       print("step", step) 
  10.  
  11. if __name__ == '__main__': 
  12.     iterator = jump_range(10) 
  13.     print(next(iterator))  # 0 
  14.     print(iterator.send(4))  # jump4; step4; 4 
  15.     print(next(iterator))  # jump None; step5; 5 
  16.     print(iterator.send(-1)) # jump -1; step4; 4 

在 Python3.3 中,生成器又引入了 yield from 關(guān)鍵字,yield from 實(shí)現(xiàn)了在生成器內(nèi)調(diào)用另外生成器的功能,可以輕易的重構(gòu)生成器,比如將多個(gè)生成器連接在一起執(zhí)行。

  1. def gen_3(): 
  2.     yield 3 
  3.  
  4. def gen_234(): 
  5.     yield 2 
  6.     yield from gen_3() 
  7.     yield 4 
  8.  
  9. def main(): 
  10.     yield 1 
  11.     yield from gen_234() 
  12.     yield 5 
  13.  
  14. for element in main(): 
  15.     print(element)  # 1,2,3,4,5 

從圖中可以看出 yield from 的特點(diǎn)。使用 itertools.chain 可以以生成器為最小組合子進(jìn)行鏈?zhǔn)浇M合,使用 itertools.cycle 可以對(duì)單獨(dú)一個(gè)生成器首尾相接,構(gòu)造一個(gè)循環(huán)鏈。

使用 yield from 時(shí)可以在生成器中從其他生成器 yield 一個(gè)值,這樣不同的生成器之間可以互相通信,這樣構(gòu)造出的生成鏈更加復(fù)雜,但生成鏈最小組合子的粒度卻精細(xì)至單個(gè) yield 對(duì)象。

2. 短暫的asynico.coroutine 與yield from

有了Python3.3中引入的yield from 這項(xiàng)工具,Python3.4 中新加入了asyncio庫(kù),并提供了一個(gè)默認(rèn)的event loop。Python3.4有了足夠的基礎(chǔ)工具進(jìn)行異步并發(fā)編程。

并發(fā)編程同時(shí)執(zhí)行多條獨(dú)立的邏輯流,每個(gè)協(xié)程都有獨(dú)立的棧空間,即使它們是都工作在同個(gè)線程中的。以下是一個(gè)示例代碼:

  1. import asyncio 
  2. import aiohttp 
  3.  
  4. @asyncio.coroutine 
  5. def fetch_page(session, url): 
  6.     response = yield from session.get(url) 
  7.     if response.status == 200: 
  8.         text = yield from response.text() 
  9.         print(text) 
  10. loop = asyncio.get_event_loop() 
  11.  
  12. session = aiohttp.ClientSession(looploop=loop) 
  13.  
  14. tasks = [ 
  15.     asyncio.ensure_future( 
  16.        fetch_page(session, "http://bigsec.com/products/redq/")), 
  17.     asyncio.ensure_future( 
  18.        fetch_page(session, "http://bigsec.com/products/warden/")) 
  19.  
  20. loop.run_until_complete(asyncio.wait(tasks)) 
  21. session.close() 
  22. loop.close() 

在 Python3.4 中,asyncio.coroutine 裝飾器是用來(lái)將函數(shù)轉(zhuǎn)換為協(xié)程的語(yǔ)法,這也是 Python ***次提供的生成器協(xié)程 。只有通過(guò)該裝飾器,生成器才能實(shí)現(xiàn)協(xié)程接口。使用協(xié)程時(shí),你需要使用 yield from 關(guān)鍵字將一個(gè) asyncio.Future 對(duì)象向下傳遞給事件循環(huán),當(dāng)這個(gè) Future 對(duì)象還未就緒時(shí),該協(xié)程就暫時(shí)掛起以處理其他任務(wù)。一旦 Future 對(duì)象完成,事件循環(huán)將會(huì)偵測(cè)到狀態(tài)變化,會(huì)將 Future 對(duì)象的結(jié)果通過(guò) send 方法方法返回給生成器協(xié)程,然后生成器恢復(fù)工作。

在以上的示例代碼中,首先實(shí)例化一個(gè) eventloop,并將其傳遞給 aiohttp.ClientSession 使用,這樣 session 就不用創(chuàng)建自己的事件循環(huán)。

此處顯式的創(chuàng)建了兩個(gè)任務(wù),只有當(dāng) fetch_page 取得 api.bigsec.com 兩個(gè) url 的數(shù)據(jù)并打印完成后,所有任務(wù)才能結(jié)束,然后關(guān)閉 session 與 loop,釋放連接資源。

當(dāng)代碼運(yùn)行到 response = yield from session.get(url)處,fetch_page 協(xié)程被掛起,隱式的將一個(gè) Future 對(duì)象傳遞給事件循環(huán),只有當(dāng) session.get() 完成后,該任務(wù)才算完成。

session.get() 內(nèi)部也是協(xié)程,其數(shù)據(jù)傳輸位于在存儲(chǔ)器山最慢的網(wǎng)絡(luò)層。當(dāng) session.get 完成時(shí),取得了一個(gè) response 對(duì)象,再傳遞給原來(lái)的 fetch_page 生成器協(xié)程,恢復(fù)其工作狀態(tài)。

為了提高速度,此處 get 方法將取得 http header 與 body 分解成兩次任務(wù),減少一次性傳輸?shù)臄?shù)據(jù)量。response.text() 即是異步請(qǐng)求 http body。

使用 dis 庫(kù)查看 fetch_page 協(xié)程的字節(jié)碼,GET_YIELD_FROM_ITER 是 yield from 的操作碼:

  1. In [4]: import dis 
  2.  
  3. In [5]: dis.dis(fetch_page) 
  4.   0 LOAD_FAST 0 (session) 
  5.   2 LOAD_ATTR 0 (get) 
  6.   4 LOAD_FAST 1 (url) 
  7.   6 CALL_FUNCTION 1 
  8.   8 GET_YIELD_FROM_ITER 
  9.   10 LOAD_CONST 0 (None) 
  10.   12 YIELD_FROM 
  11.   14 STORE_FAST 2 (response) 
  12.  
  13.   16 LOAD_FAST 2 (response) 
  14.   18 LOAD_ATTR 1 (status) 
  15.   20 LOAD_CONST 1 (200) 
  16.   22 COMPARE_OP 2 (==) 
  17.   24 POP_JUMP_IF_FALSE 48 
  18.  
  19.   26 LOAD_FAST 2 (response) 
  20.   28 LOAD_ATTR 2 (text) 
  21.   30 CALL_FUNCTION 0 
  22.   32 GET_YIELD_FROM_ITER 
  23.   34 LOAD_CONST 0 (None) 
  24.   36 YIELD_FROM 
  25.   38 STORE_FAST 3 (text) 
  26.  
  27.   40 LOAD_GLOBAL 3 (print) 
  28.   42 LOAD_FAST 3 (text) 
  29.   44 CALL_FUNCTION 1 
  30.   46 POP_TOP 
  31.   >> 48 LOAD_CONST 0 (None) 
  32.   50 RETURN_VALUE 

3. async與 await關(guān)鍵字

Python3.5 中引入了這兩個(gè)關(guān)鍵字用以取代 asyncio.coroutine 與 yield from,從語(yǔ)義上定義了原生協(xié)程關(guān)鍵字,避免了使用者對(duì)生成器協(xié)程與生成器的混淆。這個(gè)階段(3.0-3.4)使用 Python 的人不多,因此歷史包袱不重,可以進(jìn)行一些較大的革新。

await 的行為類似 yield from,但是它們異步等待的對(duì)象并不一致,yield from 等待的是一個(gè)生成器對(duì)象,而await接收的是定義了__await__方法的 awaitable 對(duì)象。

在 Python 中,協(xié)程也是 awaitable 對(duì)象,collections.abc.Coroutine 對(duì)象繼承自 collections.abc.Awaitable。

因此,將上一小節(jié)的示例代碼改寫成:

  1. import asyncio 
  2. import aiohttp 
  3.  
  4. async def fetch_page(session, url): 
  5.     response = await session.get(url) 
  6.     if response.status == 200: 
  7.         text = await response.text() 
  8.         print(text) 
  9.  
  10. loop = asyncio.get_event_loop() 
  11. session = aiohttp.ClientSession(looploop=loop) 
  12.  
  13. tasks = [ 
  14.     asyncio.ensure_future( 
  15.         fetch_page(session, "http://bigsec.com/products/redq/")), 
  16.     asyncio.ensure_future( 
  17.         fetch_page(session, "http://bigsec.com/products/warden/")) 
  18. loop.run_until_complete(asyncio.wait(tasks)) 
  19. session.close() 
  20. loop.close() 

從 Python 語(yǔ)言發(fā)展的角度來(lái)說(shuō),async/await 并非是多么偉大的改進(jìn),只是引進(jìn)了其他語(yǔ)言中成熟的語(yǔ)義,協(xié)程的基石還是在于 eventloop 庫(kù)的發(fā)展,以及生成器的完善。從結(jié)構(gòu)原理而言,asyncio 實(shí)質(zhì)擔(dān)當(dāng)?shù)慕巧且粋€(gè)異步框架,async/await 是為異步框架提供的 API,因?yàn)槭褂谜吣壳安⒉荒苊撾x asyncio 或其他異步庫(kù)使用 async/await 編寫協(xié)程代碼。即使用戶可以避免顯式地實(shí)例化事件循環(huán),比如支持 asyncio/await 語(yǔ)法的協(xié)程網(wǎng)絡(luò)庫(kù) curio,但是脫離了 eventloop 如心臟般的驅(qū)動(dòng)作用,async/await 關(guān)鍵字本身也毫無(wú)作用。

四、async/await的使用

async/await的使用

1. Future

不用回調(diào)方法編寫異步代碼后,為了獲取異步調(diào)用的結(jié)果,引入一個(gè) Future 未來(lái)對(duì)象。Future 封裝了與 loop 的交互行為,add_done_callback 方法向 epoll 注冊(cè)回調(diào)函數(shù),當(dāng) result 屬性得到返回值后,會(huì)運(yùn)行之前注冊(cè)的回調(diào)函數(shù),向上傳遞給 coroutine。但是,每一個(gè)角色各有自己的職責(zé),用 Future 向生成器 send result 以恢復(fù)工作狀態(tài)并不合適,F(xiàn)uture 對(duì)象本身的生存周期比較短,每一次注冊(cè)回調(diào)、產(chǎn)生事件、觸發(fā)回調(diào)過(guò)程后工作已經(jīng)完成。所以這里又需要在生成器協(xié)程與 Future 對(duì)象中引入一個(gè)新的對(duì)象 Task,對(duì)生成器協(xié)程進(jìn)行狀態(tài)管理。

2. Task

Task,顧名思義,是維護(hù)生成器協(xié)程狀態(tài)處理執(zhí)行邏輯的的任務(wù),Task 內(nèi)的_step 方法負(fù)責(zé)生成器協(xié)程與 EventLoop 交互過(guò)程的狀態(tài)遷移:向協(xié)程 send 一個(gè)值,恢復(fù)其工作狀態(tài),協(xié)程運(yùn)行到斷點(diǎn)后,得到新的未來(lái)對(duì)象,再處理 future 與 loop 的回調(diào)注冊(cè)過(guò)程。

3. Loop

事件循環(huán)的工作方式與用戶設(shè)想存在一些偏差,理所當(dāng)然的認(rèn)知應(yīng)是每個(gè)線程都可以有一個(gè)獨(dú)立的 loop。但是在運(yùn)行中,在主線程中才能通過(guò) asyncio.get_event_loop() 創(chuàng)建一個(gè)新的 loop,而在其他線程時(shí),使用 get_event_loop() 卻會(huì)拋錯(cuò),正確的做法應(yīng)該是 asyncio.set_event_loop() 進(jìn)行當(dāng)前線程與 loop 的顯式綁定。由于 loop 的運(yùn)作行為并不受 Python 代碼的控制,所以無(wú)法穩(wěn)定的將協(xié)程拓展到多線程中運(yùn)行。

協(xié)程在工作時(shí),并不了解是哪個(gè) loop 在對(duì)其調(diào)度,即使調(diào)用 asyncio.get_event_loop() 也不一定能獲取到真正運(yùn)行的那個(gè) loop。因此在各種庫(kù)代碼中,實(shí)例化對(duì)象時(shí)都必須顯式的傳遞當(dāng)前的 loop 以進(jìn)行綁定。

4. 另一個(gè)Future

Python 里另一個(gè) Future 對(duì)象是 concurrent.futures.Future,與 asyncio.Future 互不兼容,但容易產(chǎn)生混淆。concurrent.futures 是線程級(jí)的 Future 對(duì)象,當(dāng)使用 concurrent.futures.Executor 進(jìn)行多線程編程時(shí)用于在不同的 thread 之間傳遞結(jié)果。

5. 現(xiàn)階段asyncio生態(tài)發(fā)展的困難

  • 由于這兩個(gè)關(guān)鍵字在2014年發(fā)布的Python3.5中才被引入,發(fā)展歷史較短,在Python2與Python3割裂的大環(huán)境下,生態(tài)環(huán)境的建立并不完善;
  • 對(duì)于使用者來(lái)說(shuō),希望的邏輯是引入一個(gè)庫(kù)然后調(diào)用并獲取結(jié)果,并不關(guān)心第三方庫(kù)的內(nèi)部邏輯。然而使用協(xié)程編寫異步代碼時(shí)需要處理與事件循環(huán)的交互。對(duì)于異步庫(kù)來(lái)說(shuō),其對(duì)外封裝性并不能達(dá)到同步庫(kù)那么高。異步編程時(shí),用戶通常只會(huì)選擇一個(gè)第三方庫(kù)來(lái)處理所有HTTP邏輯。但是不同的異步實(shí)現(xiàn)方法不一致,互不兼容,分歧阻礙了社區(qū)壯大;
  • 異步代碼雖然快,但不能阻塞,一旦阻塞整個(gè)程序失效。使用多線程或多進(jìn)程的方式將調(diào)度權(quán)交給操作系統(tǒng),未免不是一種自我保護(hù);

6. 一些個(gè)人看法

其實(shí)說(shuō)了這么多,個(gè)人覺得 asyncio 雖然更加優(yōu)雅,卻實(shí)際使用上并不是像表面看起來(lái)的那么美好。首先,它不是特別的快(據(jù)說(shuō)比 gevent 快一倍),卻引入了更多的復(fù)雜性,而且從錯(cuò)誤信息 debug 更加困難。其次,這套解決方案并不成熟,最近 3.4、3.5、3.6 的三個(gè)版本,協(xié)程也有各種的細(xì)節(jié)變化,也變得越來(lái)越復(fù)雜,程序員必須隨時(shí)關(guān)注語(yǔ)言的變化才能同步。令人疑惑的是為什么 Python 一定要堅(jiān)持用生成器來(lái)實(shí)現(xiàn)協(xié)程,***又將生成器與協(xié)程進(jìn)行新老劃斷,細(xì)節(jié)卻未得到屏蔽?以目前的成熟度來(lái)看,當(dāng)你寫協(xié)程代碼時(shí),必須先去理解協(xié)程、生成器的區(qū)別,future 對(duì)象與 task 對(duì)象的職能,loop 的作用。總之,目前在生產(chǎn)環(huán)境中使用 asyncio 技術(shù)棧來(lái)解決問題并不穩(wěn)定,這個(gè)生態(tài)還需要持久的發(fā)展才能成熟。

作為程序員,在一門語(yǔ)言上深入同樣可以帶來(lái)知識(shí)的廣度。不同語(yǔ)言有不同的性格,合適的工具解決合適的問題,而以一名 Python 程序員的視角來(lái)看,大可不必堅(jiān)持寄希望于 asyncio 解決 Python 的性能問題,把在縱向上搞懂 asyncio 和這一套協(xié)程細(xì)節(jié)所需的時(shí)間拿來(lái)橫向?qū)W習(xí) Golang,尋求更合適更簡(jiǎn)單的解決方案,代碼也可以上線了。

【本文是51CTO專欄機(jī)構(gòu)“豈安科技”的原創(chuàng)文章,轉(zhuǎn)載請(qǐng)通過(guò)微信公眾號(hào)(bigsec)聯(lián)系原作者】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來(lái)源: 51CTO專欄
相關(guān)推薦

2021-09-16 09:59:13

PythonJavaScript代碼

2024-02-05 09:06:25

Python協(xié)程Asyncio庫(kù)

2021-12-09 06:41:56

Python協(xié)程多并發(fā)

2023-11-17 11:36:59

協(xié)程纖程操作系統(tǒng)

2017-09-06 09:26:03

Python生成器協(xié)程

2017-06-15 13:15:39

Python協(xié)程

2020-02-24 10:39:55

Python函數(shù)線程池

2025-06-26 04:10:00

2024-06-27 07:56:49

2023-10-24 19:37:34

協(xié)程Java

2025-02-08 09:13:40

2025-06-03 00:00:02

Go協(xié)程鎖機(jī)制

2024-12-03 15:15:22

2021-09-10 17:02:43

Python協(xié)程goroutine

2023-11-26 18:35:25

Python編程語(yǔ)言

2021-04-25 09:36:20

Go協(xié)程線程

2025-08-06 01:22:00

并發(fā)編程數(shù)據(jù)

2023-10-12 09:46:00

并發(fā)模型線程

2022-09-06 20:30:48

協(xié)程Context主線程

2021-12-27 08:04:49

架構(gòu)網(wǎng)站高并發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

亚洲乱码国产乱码精品精可以看 | 国产成人无码精品| 日韩免费成人| 性做久久久久久久免费看| 国产精品一区视频网站| 久久久久久久久久91| 精品一区免费| 7777精品伊人久久久大香线蕉的 | 成人在线视频观看| 亚洲精品视频在线观看网站| 国产在线一区二区三区播放| 中文字幕天堂在线| 亚洲人体av| 亚洲精品国精品久久99热 | www国产精品av| 国产精品视频大全| 九九九免费视频| 香蕉久久99| 日韩欧美一区二区三区在线| wwwxxx黄色片| 欧美亚洲系列| 久久精品在线免费观看| 99超碰麻豆| 中文字幕男人天堂| 香蕉久久国产| 久久99久久99精品免观看粉嫩 | 91性高潮久久久久久久| 香蕉伊大人中文在线观看| 亚洲色图一区二区| 色999五月色| 欧美 日韩 国产 精品| 久久99国产精品免费| 国产91露脸中文字幕在线| 久久高清无码视频| 天天超碰亚洲| 亚洲一级片在线看| 极品粉嫩小仙女高潮喷水久久| 亚洲黑人在线| 欧美午夜精品免费| 黄在线观看网站| 欧美日韩经典丝袜| 国产精品日日摸夜夜摸av| 久久国产精品精品国产色婷婷| 国产999久久久| 九色|91porny| 国产精品美腿一区在线看| 天天干天天干天天| 亚洲黄色影片| 欧美国产日韩一区二区| 日韩成人短视频| 日韩欧美一区二区三区在线视频| 亚洲精品视频网上网址在线观看| 日本一区二区免费视频| 亚洲无线观看| 日韩精品中文字幕一区| 亚洲精品乱码久久久久久动漫| 久久亚洲精品爱爱| 在线观看网站黄不卡| 女性隐私黄www网站视频| 日本黄色免费在线| 日韩欧美在线免费| aa在线免费观看| 欧美男人天堂| 欧美视频国产精品| 日本熟妇人妻中出| 国外成人福利视频| 91精品福利在线一区二区三区| 99精品视频国产| 日韩在线亚洲| 亚洲国产中文字幕久久网| 91av在线免费| 成人在线一区| 欧美成人小视频| 久久9999久久免费精品国产| 亚洲一区自拍| 国产精品免费视频xxxx| 国产精品亚洲lv粉色| 国产激情视频一区二区在线观看| 国产精品亚洲不卡a| 欧美一区二不卡视频| 91丨porny丨中文| 日韩videos| 蜜桃视频在线观看www社区| 亚洲欧洲成人av每日更新| 黄色小视频大全| 高h视频在线播放| 色偷偷成人一区二区三区91| 在线观看免费黄网站| 国产一区二区视频在线看| 欧美sm美女调教| 少妇按摩一区二区三区| 日韩在线综合| 久久久久久国产三级电影| 国产一级淫片免费| 日本不卡高清视频| 98国产高清一区| 亚洲色图欧美视频| 亚洲欧美影音先锋| 大陆极品少妇内射aaaaa| 69堂免费精品视频在线播放| 91精品国产91久久久久久一区二区| 国产xxxx视频| 成人羞羞视频在线看网址| 久久99精品视频一区97| 天天爱天天做天天爽| 国产精品中文字幕日韩精品| 久久99影院| 免费a级毛片在线播放| 欧美日韩美女在线| 日韩成人av免费| 精品中文字幕一区二区三区av| 久久天天躁夜夜躁狠狠躁2022| 超碰超碰超碰超碰| 国产69精品久久777的优势| 日韩在线三级| 蜜桃视频m3u8在线观看| 欧美一级高清大全免费观看| 谁有免费的黄色网址| 激情一区二区| 91色在线视频| h视频在线免费| 岛国精品视频在线播放| 国产精品成人免费一区久久羞羞| 日韩精品欧美| 国产精品高潮呻吟视频| 婷婷开心激情网| 亚洲一级电影视频| 国产男女无遮挡猛进猛出| 91久久夜色精品国产按摩| 国产91色在线|| 日本一级在线观看| 精品欧美国产一区二区三区| 亚洲欧洲国产视频| 欧美在线亚洲| 成人国产精品色哟哟| 成人免费高清在线播放| 色综合激情五月| 少妇毛片一区二区三区| 夜夜夜久久久| 精品午夜一区二区三区| missav|免费高清av在线看| 日韩欧美国产系列| 欧美另类视频在线观看| 国产精品一区二区在线看| 在线观看成人免费| 国产人妖一区| 菠萝蜜影院一区二区免费| 亚洲性在线观看| 国产精品第13页| 国产欧美一区二| 亚洲国产老妈| 4444kk亚洲人成电影在线| 综合久久2o19| 欧美tickling网站挠脚心| 国产一级淫片免费| av一区二区三区在线| 逼特逼视频在线| 免费视频一区三区| 国产精品久久久久久久久借妻 | 亚洲精品国产av| 亚洲成人免费看| 亚洲永久无码7777kkk| 亚洲女优在线| 日韩在线电影一区| 精品99re| 午夜精品福利视频| 可以在线观看的黄色| 欧美午夜宅男影院| www.99re7| 99久免费精品视频在线观看| 黄色免费观看视频网站| 欧美精品一二| 亚洲va电影大全| 成人影音在线| 亚洲天堂影视av| 国产精品无码天天爽视频| 一区二区不卡在线视频 午夜欧美不卡在 | 国产一区二区三区四区五区入口| 天天成人综合网| 99ri日韩精品视频| 青青精品视频播放| 里番在线观看网站| 亚洲福利在线视频| 久久久久久久亚洲| 一区二区三区自拍| 成年人网站免费在线观看| 蜜臀av一级做a爰片久久| 亚洲av综合色区| 亚洲三级性片| 亚洲xxxxx性| 筱崎爱全乳无删减在线观看| 少妇高潮久久77777| 国产刺激高潮av| 在线观看亚洲a| 日本熟妇成熟毛茸茸| 国产亚洲精品bt天堂精选| 日韩欧美中文视频| 麻豆精品网站| 嫩草影院中文字幕| 国产一区99| 99精品国产一区二区| 欧美黑人一区| 久久久久久久久网站| 成人免费一区二区三区视频网站| 亚洲精品一区二区三区香蕉| 自拍偷拍第八页| 黄色一区二区在线观看| 麻豆网址在线观看| 久久久久9999亚洲精品| 国产chinesehd精品露脸| 青青草国产精品亚洲专区无| 777777av| 午夜欧美精品| 正义之心1992免费观看全集完整版| 色婷婷av一区二区三区丝袜美腿| 成人午夜在线视频一区| 桃花岛成人影院| 97国产精品免费视频| 国产不卡在线| 中文字幕视频一区二区在线有码 | 视频精品二区| 国产在线拍揄自揄视频不卡99| 麻豆视频在线看| 欧美精品videossex88| 国产成人高清精品| 久久精品国产清自在天天线| 国产视频在线看| 亚洲美女久久久| 污污的视频网站在线观看| 欧美成人欧美edvon| 国产精品久久无码一三区| 欧美影院精品一区| 国产一级片免费视频| 欧美视频在线观看免费| www.国产成人| 午夜久久久久久| 久久久久久久99| 亚洲国产人成综合网站| 久操免费在线视频| 一区二区三区蜜桃网| 国产成人综合在线视频| 亚洲欧洲三级电影| 欧美一区免费观看| 亚洲免费色视频| 欧美日韩免费做爰视频| 亚洲欧美日韩国产手机在线| www.av免费| 亚洲免费看黄网站| 91插插插插插插| 亚洲嫩草精品久久| 欧美精品videos极品| 亚洲国产日韩a在线播放| 久久精品国产亚洲av高清色欲| 亚洲国产一区二区视频| 日韩精品无码一区二区| 精品久久久在线观看| 日韩精品在线观看免费| 一本高清dvd不卡在线观看| 国产一级淫片a视频免费观看| 色综合久久久久久久久久久| 中文av免费观看| 欧美精品1区2区3区| www.五月激情| 亚洲精品狠狠操| 中文字幕在线免费| 另类视频在线观看| 国产蜜臀在线| 国产91亚洲精品| 伊人久久综合网另类网站| 亚洲在线免费视频| 日韩高清一级| 午夜欧美性电影| 欧美日韩一区二区高清| www.com毛片| 免费一级片91| 师生出轨h灌满了1v1| 91玉足脚交白嫩脚丫在线播放| 国产精品国产三级国产专业不 | 国产高清www| 久久人人97超碰国产公开结果| 少妇一级淫免费播放| 国产成人激情av| 亚洲专区区免费| 自拍偷拍亚洲综合| 国产性xxxx高清| 欧美巨大另类极品videosbest | 青青草97国产精品麻豆| 欧美美女黄色网| 香蕉成人久久| 精产国品一二三区| www久久精品| 欧美国产精品一二三| 一本久久a久久精品亚洲| 99国产精品欲| 国产亚洲美女精品久久久| 在线免费观看污| 国产精品高潮在线| 国产+成+人+亚洲欧洲在线| 午夜精品一区二区在线观看| 亚洲精选久久| 国产乱码一区二区三区四区| 久久久久国色av免费看影院| 538精品在线观看| 欧美综合在线视频| 神宫寺奈绪一区二区三区| 日韩在线观看网址| 美女100%一区| 国产98在线|日韩| 91麻豆国产自产在线观看亚洲| 中文字幕无码精品亚洲35| 国产一区二区调教| 日本成人午夜影院| 性做久久久久久免费观看| 国产视频aaa| 日日摸夜夜添一区| 电影一区二区三区| 国产日韩欧美亚洲一区| 亚洲综合色站| 91亚洲精品久久久蜜桃借种| 久久女同性恋中文字幕| 久久久91视频| 日韩一区二区中文字幕| av在线日韩国产精品| 欧美综合在线观看| 国内精品免费| 成年人深夜视频| 国产黑丝在线一区二区三区| 天堂а√在线中文在线鲁大师| 日本久久电影网| 全部免费毛片在线播放网站| 国模精品系列视频| 亚洲精品在线a| 久久久99精品视频| 国产伦精一区二区三区| 日韩高清dvd碟片| 欧美日韩久久一区二区| 波多野结衣在线影院| 国产成人自拍视频在线观看| 偷拍亚洲色图| 日本精品免费在线观看| 成年人网站91| 日本五十熟hd丰满| 亚洲成年网站在线观看| 国精一区二区三区| 国产乱码精品一区二区三区日韩精品| 欧美+日本+国产+在线a∨观看| 污污视频在线免费| 一区二区三区毛片| 亚洲黄色小说网址| 国产+人+亚洲| 亚瑟一区二区三区四区| 免费观看精品视频| 国产欧美一区视频| 中文在线字幕av| 久久精品电影网站| 精品一区91| 黄色激情在线视频| 99久久久久久99| 无码人妻精品一区二区| 国产一区二区久久精品| 啪啪av大全导航福利综合导航| 中文字幕欧美人与畜| 国产精品一品二品| 国产大片中文字幕在线观看| 亚洲精品白浆高清久久久久久| 鲁鲁在线中文| 少妇精品久久久久久久久久| 久久精品国产一区二区三区免费看| 美国黄色片视频| 欧美成人精品福利| 亚洲一区资源| 亚洲一区二区不卡视频| 国产成人免费视频一区| 久久不卡免费视频| 中文字幕亚洲国产| 日韩有吗在线观看| 欧美成人免费高清视频| 国产精品久久久久精k8| 超碰福利在线观看| 日韩av电影在线播放| 婷婷久久综合| 李丽珍裸体午夜理伦片| 欧美丝袜自拍制服另类| 亚洲妇熟xxxx妇色黄| 久久综合九色综合久99| 久久成人av少妇免费| 久久婷婷国产麻豆91| 亚洲一区www| 91精品入口| 天天爱天天操天天干| 亚洲一区二区视频| 成人在线二区| 国产欧美综合精品一区二区| 久久机这里只有精品| 久久午夜免费视频| 久久久精品亚洲| 国语产色综合| 女同性恋一区二区三区| 欧美日韩精品一区视频| 高清视频在线观看三级|