成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

包含實現(xiàn)python異步函數(shù)的詞條

Python異步編程全攻略

如果你厭倦了多線程,不妨試試python的異步編程,再引入async, await關鍵字之后語法變得更加簡潔和直觀,又經過幾年的生態(tài)發(fā)展,現(xiàn)在是一個很不錯的并發(fā)模型。

創(chuàng)新互聯(lián)建站是專業(yè)的膠州網站建設公司,膠州接單;提供成都網站設計、網站制作,網頁設計,網站設計,建網站,PHP網站建設等專業(yè)做網站服務;采用PHP框架,可快速的進行膠州網站開發(fā)網頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網站,專業(yè)的做網站團隊,希望更多企業(yè)前來合作!

下面介紹一下python異步編程的方方面面。

因為GIL的存在,所以Python的多線程在CPU密集的任務下顯得無力,但是對于IO密集的任務,多線程還是足以發(fā)揮多線程的優(yōu)勢的,而異步也是為了應對IO密集的任務,所以兩者是一個可以相互替代的方案,因為設計的不同,理論上異步要比多線程快,因為異步的花銷更少, 因為不需要額外系統(tǒng)申請額外的內存,而線程的創(chuàng)建跟系統(tǒng)有關,需要分配一定量的內存,一般是幾兆,比如linux默認是8MB。

雖然異步很好,比如可以使用更少的內存,比如更好地控制并發(fā)(也許你并不這么認為:))。但是由于async/await 語法的存在導致與之前的語法有些割裂,所以需要適配,需要付出額外的努力,再者就是生態(tài)遠遠沒有同步編程強大,比如很多庫還不支持異步,所以你需要一些額外的適配。

為了不給其他網站帶來困擾,這里首先在自己電腦啟動web服務用于測試,代碼很簡單。

本文所有依賴如下:

所有依賴可通過代碼倉庫的requirements.txt一次性安裝。

首先看一個錯誤的例子

輸出如下:

發(fā)現(xiàn)花費了3秒,不符合預期呀。。。。這是因為雖然用了協(xié)程,但是每個協(xié)程是串行的運行,也就是說后一個等前一個完成之后才開始,那么這樣的異步代碼并沒有并發(fā),所以我們需要讓這些協(xié)程并行起來

為了讓代碼變動的不是太多,所以這里用了一個笨辦法來等待所有任務完成, 之所以在main函數(shù)中等待是為了不讓ClientSession關閉, 如果你移除了main函數(shù)中的等待代碼會發(fā)現(xiàn)報告異常 RuntimeError: Session is closed ,而代碼里的解決方案非常的不優(yōu)雅,需要手動的等待,為了解決這個問題,我們再次改進代碼。

這里解決的方式是通過 asyncio.wait 方法等待一個協(xié)程列表,默認是等待所有協(xié)程結束后返回,會返回一個完成(done)列表,以及一個待辦(pending)列表。

如果我們不想要協(xié)程對象而是結果,那么我們可以使用 asyncio.gather

結果輸出如下:

通過 asyncio.ensure_future 我們就能創(chuàng)建一個協(xié)程,跟調用一個函數(shù)差別不大,為了等待所有任務完成之后退出,我們需要使用 asyncio.wait 等方法來等待,如果只想要協(xié)程輸出的結果,我們可以使用 asyncio.gather 來獲取結果。

雖然前面能夠隨心所欲的創(chuàng)建協(xié)程,但是就像多線程一樣,我們也需要處理協(xié)程之間的同步問題,為了保持語法及使用情況的一致,多線程中用到的同步功能,asyncio中基本也能找到, 并且用法基本一致,不一致的地方主要是需要用異步的關鍵字,比如 async with/ await 等

通過鎖讓并發(fā)慢下來,讓協(xié)程一個一個的運行。

輸出如下:

通過觀察很容易發(fā)現(xiàn),并發(fā)的速度因為鎖而慢下來了,因為每次只有一個協(xié)程能獲得鎖,所以并發(fā)變成了串行。

通過事件來通知特定的協(xié)程開始工作,假設有一個任務是根據(jù)http響應結果選擇是否激活。

輸出如下:

可以看到事件(Event)等待者都是在得到響應內容之后輸出,并且事件(Event)可以是多個協(xié)程同時等待。

上面的事件雖然很棒,能夠在不同的協(xié)程之間同步狀態(tài),并且也能夠一次性同步所有的等待協(xié)程,但是還不夠精細化,比如想通知指定數(shù)量的等待協(xié)程,這個時候Event就無能為力了,所以同步原語中出現(xiàn)了Condition。

輸出如下:

可以看到,前面兩個等待的協(xié)程是在同一時刻完成,而不是全部等待完成。

通過創(chuàng)建協(xié)程的數(shù)量來控制并發(fā)并不是非常優(yōu)雅的方式,所以可以通過信號量的方式來控制并發(fā)。

輸出如下:

可以發(fā)現(xiàn),雖然同時創(chuàng)建了三個協(xié)程,但是同一時刻只有兩個協(xié)程工作,而另外一個協(xié)程需要等待一個協(xié)程讓出信號量才能運行。

無論是協(xié)程還是線程,任務之間的狀態(tài)同步還是很重要的,所以有了應對各種同步機制的同步原語,因為要保證一個資源同一個時刻只能一個任務訪問,所以引入了鎖,又因為需要一個任務等待另一個任務,或者多個任務等待某個任務,因此引入了事件(Event),但是為了更精細的控制通知的程度,所以又引入了條件(Condition), 通過條件可以控制一次通知多少的任務。

有時候的并發(fā)需求是通過一個變量控制并發(fā)任務的并發(fā)數(shù)而不是通過創(chuàng)建協(xié)程的數(shù)量來控制并發(fā),所以引入了信號量(Semaphore),這樣就可以在創(chuàng)建的協(xié)程數(shù)遠遠大于并發(fā)數(shù)的情況下讓協(xié)程在指定的并發(fā)量情況下并發(fā)。

不得不承認異步編程相比起同步編程的生態(tài)要小的很多,所以不可能完全異步編程,因此需要一種方式兼容。

多線程是為了兼容同步得代碼。

多進程是為了利用CPU多核的能力。

輸出如下:

可以看到總耗時1秒,說明所有的線程跟進程是同時運行的。

下面是本人使用過的一些異步庫,僅供參考

web框架

http客戶端

數(shù)據(jù)庫

ORM

雖然異步庫發(fā)展得還算不錯,但是中肯的說并沒有覆蓋方方面面。

雖然我鼓勵大家嘗試異步編程,但是本文的最后卻是讓大家謹慎的選擇開發(fā)環(huán)境,如果你覺得本文的并發(fā),同步,兼容多線程,多進程不值得一提,那么我十分推薦你嘗試以異步編程的方式開始一個新的項目,如果你對其中一些還有疑問或者你確定了要使用的依賴庫并且大多數(shù)是沒有異步庫替代的,那么我還是建議你直接按照自己擅長的同步編程開始。

異步編程雖然很不錯,不過,也許你并不需要。

python2.7怎么實現(xiàn)異步

改進之前

之前,我的查詢步驟很簡單,就是:

前端提交查詢請求 -- 建立數(shù)據(jù)庫連接 -- 新建游標 -- 執(zhí)行命令 -- 接受結果 -- 關閉游標、連接

這幾大步驟的順序執(zhí)行。

這里面當然問題很大:

建立數(shù)據(jù)庫連接實際上就是新建一個套接字。這是進程間通信的幾種方法里,開銷最大的了。

在“執(zhí)行命令”和“接受結果”兩個步驟中,線程在阻塞在數(shù)據(jù)庫內部的運行過程中,數(shù)據(jù)庫連接和游標都處于閑置狀態(tài)。

這樣一來,每一次查詢都要順序的新建數(shù)據(jù)庫連接,都要阻塞在數(shù)據(jù)庫返回結果的過程中。當前端提交大量查詢請求時,查詢效率肯定是很低的。

第一次改進

之前的模塊里,問題最大的就是第一步——建立數(shù)據(jù)庫連接套接字了。如果能夠一次性建立連接,之后查詢能夠反復服用這個連接就好了。

所以,首先應該把數(shù)據(jù)庫查詢模塊作為一個單獨的守護進程去執(zhí)行,而前端app作為主進程響應用戶的點擊操作。那么兩條進程怎么傳遞消息呢?翻了幾天Python文檔,終于構思出來:用隊列queue作為生產者(web前端)向消費者(數(shù)據(jù)庫后端)傳遞任務的渠道。生產者,會與SQL命令一起,同時傳遞一個管道pipe的連接對象,作為任務完成后,回傳結果的渠道。確保,任務的接收方與發(fā)送方保持一致。

作為第二個問題的解決方法,可以使用線程池來并發(fā)獲取任務隊列中的task,然后執(zhí)行命令并回傳結果。

第二次改進

第一次改進的效果還是很明顯的,不用任何測試手段。直接點擊頁面鏈接,可以很直觀地感覺到反應速度有很明顯的加快。

但是對于第二個問題,使用線程池還是有些欠妥當。因為,CPython解釋器存在GIL問題,所有線程實際上都在一個解釋器進程里調度。線程稍微開多一點,解釋器進程就會頻繁的切換線程,而線程切換的開銷也不小。線程多一點,甚至會出現(xiàn)“抖動”問題(也就是剛剛喚醒一個線程,就進入掛起狀態(tài),剛剛換到棧幀或內存的上下文,又被換回內存或者磁盤),效率大大降低。也就是說,線程池的并發(fā)量很有限。

試過了多進程、多線程,只能在單個線程里做文章了。

Python中的asyncio庫

Python里有大量的協(xié)程庫可以實現(xiàn)單線程內的并發(fā)操作,比如Twisted、Gevent等等。Python官方在3.5版本里提供了asyncio庫同樣可以實現(xiàn)協(xié)程并發(fā)。asyncio庫大大降低了Python中協(xié)程的實現(xiàn)難度,就像定義普通函數(shù)那樣就可以了,只是要在def前面多加一個async關鍵詞。async def函數(shù)中,需要阻塞在其他async def函數(shù)的位置前面可以加上await關鍵詞。

import asyncio

async def wait():

await asyncio.sleep(2)

async def execute(task):

process_task(task)

await wait()

continue_job()

async def函數(shù)的執(zhí)行稍微麻煩點。需要首先獲取一個loop對象,然后由這個對象代為執(zhí)行async def函數(shù)。

loop = asyncio.get_event_loop()

loop.run_until_complete(execute(task))

loop.close()

loop在執(zhí)行execute(task)函數(shù)時,如果遇到await關鍵字,就會暫時掛起當前協(xié)程,轉而去執(zhí)行其他阻塞在await關鍵詞的協(xié)程,從而實現(xiàn)協(xié)程并發(fā)。

不過需要注意的是,run_until_complete()函數(shù)本身是一個阻塞函數(shù)。也就是說,當前線程會等候一個run_until_complete()函數(shù)執(zhí)行完畢之后,才會繼續(xù)執(zhí)行下一部函數(shù)。所以下面這段代碼并不能并發(fā)執(zhí)行。

for task in task_list:

loop.run_until_complete(task)

對與這個問題,asyncio庫也有相應的解決方案:gather函數(shù)。

loop = asyncio.get_event_loop()

tasks = [asyncio.ensure_future(execute(task))

for task in task_list]

loop.run_until_complete(asyncio.gather(*tasks))

loop.close()

當然了,async def函數(shù)的執(zhí)行并不只有這兩種解決方案,還有call_soon與run_forever的配合執(zhí)行等等,更多內容還請參考官方文檔。

Python下的I/O多路復用

協(xié)程,實際上,也存在上下文切換,只不過開銷很輕微。而I/O多路復用則完全不存在這個問題。

目前,Linux上比較火的I/O多路復用API要算epoll了。Tornado,就是通過調用C語言封裝的epoll庫,成功解決了C10K問題(當然還有Pypy的功勞)。

在Linux里查文檔,可以看到epoll只有三類函數(shù),調用起來比較方便易懂。

創(chuàng)建epoll對象,并返回其對應的文件描述符(file descriptor)。

int epoll_create(int size);

int epoll_create1(int flags);

控制監(jiān)聽事件。第一個參數(shù)epfd就對應于前面命令創(chuàng)建的epoll對象的文件描述符;第二個參數(shù)表示該命令要執(zhí)行的動作:監(jiān)聽事件的新增、修改或者刪除;第三個參數(shù),是要監(jiān)聽的文件對應的描述符;第四個,代表要監(jiān)聽的事件。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

等候。這是一個阻塞函數(shù),調用者會等候內核通知所注冊的事件被觸發(fā)。

int epoll_wait(int epfd, struct epoll_event *events,

int maxevents, int timeout);

int epoll_pwait(int epfd, struct epoll_event *events,

int maxevents, int timeout,

const sigset_t *sigmask);

在Python的select庫里:

select.epoll()對應于第一類創(chuàng)建函數(shù);

epoll.register(),epoll.unregister(),epoll.modify()均是對控制函數(shù)epoll_ctl的封裝;

epoll.poll()則是對等候函數(shù)epoll_wait的封裝。

Python里epoll相關API的最大問題應該是在epoll.poll()。相比于其所封裝的epoll_wait,用戶無法手動指定要等候的事件,也就是后者的第二個參數(shù)struct epoll_event *events。沒法實現(xiàn)精確控制。因此只能使用替代方案:select.select()函數(shù)。

根據(jù)Python官方文檔,select.select(rlist, wlist, xlist[, timeout])是對Unix系統(tǒng)中select函數(shù)的直接調用,與C語言API的傳參很接近。前三個參數(shù)都是列表,其中的元素都是要注冊到內核的文件描述符。如果想用自定義類,就要確保實現(xiàn)了fileno()方法。

其分別對應于:

rlist: 等候直到可讀

wlist: 等候直到可寫

xlist: 等候直到異常。這個異常的定義,要查看系統(tǒng)文檔。

select.select(),類似于epoll.poll(),先注冊文件和事件,然后保持等候內核通知,是阻塞函數(shù)。

實際應用

Psycopg2庫支持對異步和協(xié)程,但和一般情況下的用法略有區(qū)別。普通數(shù)據(jù)庫連接支持不同線程中的不同游標并發(fā)查詢;而異步連接則不支持不同游標的同時查詢。所以異步連接的不同游標之間必須使用I/O復用方法來協(xié)調調度。

所以,我的大致實現(xiàn)思路是這樣的:首先并發(fā)執(zhí)行大量協(xié)程,從任務隊列中提取任務,再向連接池請求連接,創(chuàng)建游標,然后執(zhí)行命令,并返回結果。在獲取游標和接受查詢結果之前,均要阻塞等候內核通知連接可用。

其中,連接池返回連接時,會根據(jù)引用連接的協(xié)程數(shù)量,返回負載最輕的連接。這也是自己定義AsyncConnectionPool類的目的。

我的代碼位于:bottle-blog/dbservice.py

存在問題

當然了,這個流程目前還一些問題。

首先就是每次輪詢拿到任務之后,都會走這么一個流程。

獲取連接 -- 新建游標 -- 執(zhí)行任務 -- 關閉游標 -- 取消連接引用

本來,最好的情況應該是:在輪詢之前,就建好游標;在輪詢時,直接等候內核通知,執(zhí)行相應任務。這樣可以減少輪詢時的任務量。但是如果協(xié)程提前對應好連接,那就不能保證在獲取任務時,保持各連接負載均衡了。

所以這一塊,還有工作要做。

還有就是epoll沒能用上,有些遺憾。

以后打算寫點C語言的內容,或者用Python/C API,或者用Ctypes包裝共享庫,來實現(xiàn)epoll的調用。

最后,請允許我吐槽一下Python的epoll相關文檔:簡直太弱了?。?!必須看源碼才能弄清楚功能。

python里怎么實現(xiàn)異步調用

本文實例講述了python使用multiprocessing模塊實現(xiàn)帶回調函數(shù)的異步調用方法。分享給大家供大家參考。具體分析如下:

multipressing模塊是python 2.6版本加入的,通過這個模塊可以輕松實現(xiàn)異步調用

from multiprocessing import Pool

def f(x):

return x*x

if __name__ == '__main__':

pool = Pool(processes=1)

# Start a worker processes.

result = pool.apply_async(f, [10], callback)

# Evaluate "f(10)" asynchronously calling callback when finished.

希望本文所述對大家的Python程序設計有所幫助。

Python異步編程--greenlet

? 是使用一個任務調度器和一些生成器或者協(xié)程實現(xiàn)協(xié)作式用戶空間多線程的一種偽并發(fā)機制,即所謂的微線程。

?當創(chuàng)建一個 greenlet 時,它會獲得一個最初為空的堆棧;當你第一次切換到它時,它開始運行一個指定的函數(shù),它可能會調用其他函數(shù),切換出greenlet等。安裝 pip install greenlet。

控制臺輸出:

理解python異步機制

最重要的是生成器函數(shù)碰到y(tǒng)ield停止執(zhí)行,收到next或send才會繼續(xù)執(zhí)行的機制。

而且send方法令我們可以傳遞值到生成器暫停的地方。

生成器執(zhí)行結束拋出 StopIteration 異常。

yield from用于把其他生成器當做子例程調用。

然后它可以被其他用 async def 定義的的協(xié)程函數(shù)B和C await ,只有當 await 返回時,B和C才繼續(xù)執(zhí)行。

這樣我們就可以有效地控制B和C的執(zhí)行順序。

然后我們創(chuàng)建了一個調度器,它對列表進行了兩次深拷貝以避免問題。它循環(huán)協(xié)程隊列,使用 send 方法對每個協(xié)程依次遞進,如果有協(xié)程已經完成則將其移出隊列,當列表中的協(xié)程全部完成時結束。

然后通過 args=coro.send(None) 與該函數(shù)碰撞,得到含有 delay 參數(shù)的字典作為 send 的返回值。便可以判斷出是否調用調度器的睡眠機制。

最后在調度器中實現(xiàn)每一次協(xié)程列表循環(huán)結束后判斷在睡眠列表中的協(xié)程是否有到時間的,到時間或時間超出則添加到運行協(xié)程列表中進入循環(huán)執(zhí)行。如果運行列表中的協(xié)程都執(zhí)行完了,則查看睡眠列表中的協(xié)程中還需睡眠的最少時間,線程睡眠,睡眠完成再將其添加到運行隊列。

該裝飾器能將一個比較耗時的計算函數(shù)封裝為一個協(xié)程,使其可以被其他協(xié)程 await 。在調度器中利用 send 函數(shù)的返回值可以獲取它的類型為 background 、函數(shù)入口地址以及函數(shù)的傳參,然后在調度器中按相應機制執(zhí)行。

第二部分 是在調度器中的修改:我們讓調度器類擁有了一個私有的 concurrent.futures.ThreadPoolExecutor() 對象。并在運行協(xié)程隊列的循環(huán)判斷中將 background 類型的操作提交給線程池對象,并將當前的協(xié)程移出運行隊列,添加到 futures 隊列中。然后在每次運行隊列循環(huán)后判斷 futures 中的任務是否有完成的(使用的參數(shù)為一旦有任一任務完成或被取消都返回),如果主線程此時處于將要睡眠的狀態(tài),就等待相應的時間,沒有的話則立刻返回,下次再查詢,完成的任務將其所在協(xié)程帶入運行隊列,任務結果通過調度器 send 傳回該協(xié)程。

python異步有哪些方式

yield相當于return,他將相應的值返回給調用next()或者send()的調用者,從而交出了CPU使用權,而當調用者再次調用next()或者send()的時候,又會返回到y(tǒng)ield中斷的地方,如果send有參數(shù),還會將參數(shù)返回給yield賦值的變量,如果沒有就和next()一樣賦值為None。但是這里會遇到一個問題,就是嵌套使用generator時外層的generator需要寫大量代碼,看如下示例:?

注意以下代碼均在Python3.6上運行調試

#!/usr/bin/env python# encoding:utf-8def inner_generator():

i = 0

while True:

i = yield i ? ? ? ?if i 10: ? ? ? ? ? ?raise StopIterationdef outer_generator():

print("do something before yield")

from_inner = 0

from_outer = 1

g = inner_generator()

g.send(None) ? ?while 1: ? ? ? ?try:

from_inner = g.send(from_outer)

from_outer = yield from_inner ? ? ? ?except StopIteration: ? ? ? ? ? ?breakdef main():

g = outer_generator()

g.send(None)

i = 0

while 1: ? ? ? ?try:

i = g.send(i + 1)

print(i) ? ? ? ?except StopIteration: ? ? ? ? ? ?breakif __name__ == '__main__':

main()1234567891011121314151617181920212223242526272829303132333435363738394041

為了簡化,在Python3.3中引入了yield from

yield from

使用yield from有兩個好處,

1、可以將main中send的參數(shù)一直返回給最里層的generator,?

2、同時我們也不需要再使用while循環(huán)和send (), next()來進行迭代。

我們可以將上邊的代碼修改如下:

def inner_generator():

i = 0

while True:

i = yield i ? ? ? ?if i 10: ? ? ? ? ? ?raise StopIterationdef outer_generator():

print("do something before coroutine start") ? ?yield from inner_generator()def main():

g = outer_generator()

g.send(None)

i = 0

while 1: ? ? ? ?try:

i = g.send(i + 1)

print(i) ? ? ? ?except StopIteration: ? ? ? ? ? ?breakif __name__ == '__main__':

main()1234567891011121314151617181920212223242526

執(zhí)行結果如下:

do something before coroutine start123456789101234567891011

這里inner_generator()中執(zhí)行的代碼片段我們實際就可以認為是協(xié)程,所以總的來說邏輯圖如下:?

接下來我們就看下究竟協(xié)程是啥樣子

協(xié)程coroutine

協(xié)程的概念應該是從進程和線程演變而來的,他們都是獨立的執(zhí)行一段代碼,但是不同是線程比進程要輕量級,協(xié)程比線程還要輕量級。多線程在同一個進程中執(zhí)行,而協(xié)程通常也是在一個線程當中執(zhí)行。它們的關系圖如下:

我們都知道Python由于GIL(Global Interpreter Lock)原因,其線程效率并不高,并且在*nix系統(tǒng)中,創(chuàng)建線程的開銷并不比進程小,因此在并發(fā)操作時,多線程的效率還是受到了很大制約的。所以后來人們發(fā)現(xiàn)通過yield來中斷代碼片段的執(zhí)行,同時交出了cpu的使用權,于是協(xié)程的概念產生了。在Python3.4正式引入了協(xié)程的概念,代碼示例如下:

import asyncio# Borrowed from countdown(number, n):

while n 0:

print('T-minus', n, '({})'.format(number)) ? ? ? ?yield from asyncio.sleep(1)

n -= 1loop = asyncio.get_event_loop()

tasks = [

asyncio.ensure_future(countdown("A", 2)),

asyncio.ensure_future(countdown("B", 3))]

loop.run_until_complete(asyncio.wait(tasks))

loop.close()12345678910111213141516

示例顯示了在Python3.4引入兩個重要概念協(xié)程和事件循環(huán),?

通過修飾符@asyncio.coroutine定義了一個協(xié)程,而通過event loop來執(zhí)行tasks中所有的協(xié)程任務。之后在Python3.5引入了新的async await語法,從而有了原生協(xié)程的概念。

async await

在Python3.5中,引入了ayncawait 語法結構,通過”aync def”可以定義一個協(xié)程代碼片段,作用類似于Python3.4中的@asyncio.coroutine修飾符,而await則相當于”yield from”。

先來看一段代碼,這個是我剛開始使用asyncawait語法時,寫的一段小程序。

#!/usr/bin/env python# encoding:utf-8import asyncioimport requestsimport time

async def wait_download(url):

response = await requets.get(url)

print("get {} response complete.".format(url))

async def main():

start = time.time()

await asyncio.wait([

wait_download(""),

wait_download(""),

wait_download("")])

end = time.time()

print("Complete in {} seconds".format(end - start))

loop = asyncio.get_event_loop()

loop.run_until_complete(main())12345678910111213141516171819202122232425

這里會收到這樣的報錯:

Task exception was never retrieved

future: Task finished coro=wait_download() done, defined at asynctest.py:9 exception=TypeError("object Response can't be used in 'await' expression",)

Traceback (most recent call last):

File "asynctest.py", line 10, in wait_download

data = await requests.get(url)

TypeError: object Response can't be used in 'await' expression123456

這是由于requests.get()函數(shù)返回的Response對象不能用于await表達式,可是如果不能用于await,還怎么樣來實現(xiàn)異步呢??

原來Python的await表達式是類似于”yield from”的東西,但是await會去做參數(shù)檢查,它要求await表達式中的對象必須是awaitable的,那啥是awaitable呢? awaitable對象必須滿足如下條件中其中之一:

1、A native coroutine object returned from a native coroutine function .

原生協(xié)程對象

2、A generator-based coroutine object returned from a function decorated with types.coroutine() .

types.coroutine()修飾的基于生成器的協(xié)程對象,注意不是Python3.4中asyncio.coroutine

3、An object with an await method returning an iterator.

實現(xiàn)了await method,并在其中返回了iterator的對象

根據(jù)這些條件定義,我們可以修改代碼如下:

#!/usr/bin/env python# encoding:utf-8import asyncioimport requestsimport time

async def download(url): # 通過async def定義的函數(shù)是原生的協(xié)程對象

response = requests.get(url)

print(response.text)

async def wait_download(url):

await download(url) # 這里download(url)就是一個原生的協(xié)程對象

print("get {} data complete.".format(url))

async def main():

start = time.time()

await asyncio.wait([

wait_download(""),

wait_download(""),

wait_download("")])

end = time.time()

print("Complete in {} seconds".format(end - start))

loop = asyncio.get_event_loop()

loop.run_until_complete(main())123456789101112131415161718192021222324252627282930

好了現(xiàn)在一個真正的實現(xiàn)了異步編程的小程序終于誕生了。?

而目前更牛逼的異步是使用uvloop或者pyuv,這兩個最新的Python庫都是libuv實現(xiàn)的,可以提供更加高效的event loop。

uvloop和pyuv

pyuv實現(xiàn)了Python2.x和3.x,但是該項目在github上已經許久沒有更新了,不知道是否還有人在維護。?

uvloop只實現(xiàn)了3.x, 但是該項目在github上始終活躍。

它們的使用也非常簡單,以uvloop為例,只需要添加以下代碼就可以了

import asyncioimport uvloop

asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())123

本文題目:包含實現(xiàn)python異步函數(shù)的詞條
當前URL:http://jinyejixie.com/article10/hsihgo.html

成都網站建設公司_創(chuàng)新互聯(lián),為您提供營銷型網站建設、品牌網站制作App設計、虛擬主機、網站內鏈、定制網站

廣告

聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司
尖扎县| 乌苏市| 尖扎县| 麟游县| 景泰县| 调兵山市| 安徽省| 青州市| 平遥县| 双江| 曲阜市| 灌阳县| 盐山县| 奇台县| 上饶县| 营山县| 乌拉特后旗| 和林格尔县| 康平县| 万年县| 淮滨县| 贵港市| 称多县| 布尔津县| 阳信县| 垫江县| 永善县| 织金县| 庆城县| 定日县| 南宁市| 仙桃市| 尤溪县| 通榆县| 垣曲县| 太原市| 噶尔县| 横峰县| 天津市| 德格县| 磐安县|