導航:首頁 > 編程語言 > Python強制等待非同步函數

Python強制等待非同步函數

發布時間:2023-05-16 21:06:34

python 非同步是什麼意思

非同步是計算機多線程的非同步處理。與同步處理相對,非同步處理不用阻塞當前線程來等待處理完成,而是允許後續操作,直至其它線程將處理完成,並回調通知此線程。

② Python selenium 三種等待方式


很多人在群里問,戚櫻彎這個下拉框定位不到、那個彈出框定位不到各種定位不到,其實大多數情況下就是兩種問題:1 有frame,2 沒有加等待。殊不知,你的代碼運行速度是什麼量級的,而瀏覽器載入渲染速度又是什麼量級的,就好比閃電俠和凹凸曼約好去打怪獸,然後閃電俠打完回來之後問凹凸曼你為啥還在穿鞋沒出門?凹凸曼分分中內心一萬只羊駝飛過,欺負哥速度慢,哥不跟你玩了,拋個異常撂挑子了。
那麼怎麼才能照顧到凹凸曼緩慢的載入速度呢?只有一個辦法,那就是等嘍。說到等,又有三種等法,且聽博主一一道來:
1. 強制等待
第一種也是最簡單粗暴的一種辦法就是強制等待sleep(xx),強制讓閃電俠等xx時間,不管凹凸曼能不能跟上速度,還是已經提前到了,都必須等xx時間。
看代碼:
?
1
234
5678
# -*- coding: utf-8 -*-
from
selenium
import
webdriver
from
time
import
sleep
driver
=
webdriver.Firefox()
driver.get(
sleep(3)
# 強制等待3秒再執行下一步
print
driver.current_url
driver.quit()
這種叫強制等待,不管你瀏覽器是否載入完了,程序都得等待3秒,3秒一到,繼續頌姿執行下面的代碼,作為調試很有用,有時候也可以在代碼里這樣等待,不過不建議總用這種等待方式,太死板,嚴重影響程序執行速度。
2. 隱性等待
第二種辦法叫隱性等待,implicitly_wait(xx),隱性等待的意義是:閃電俠和凹凸曼約定好,不論閃電俠去哪兒,都要等凹凸曼高悶xx秒,如果凹凸曼在這段時間內來了,則倆人立即出發去打怪獸,如果凹凸曼在規定時間內沒到,則閃電俠自己去,那自然就等著凹凸曼給你拋異常吧。
看代碼:
?
1234567
# -*- coding: utf-8 -*-
from
selenium
import
webdriver
driver
=
webdriver.Firefox()
③ python wait()函數問題

看了你發的函數:
def Wait(self):
self._app.MainLoop()
看名字應該是啟動了阻塞循環,去處理app的請求,這個就是需要一直運行的,因為一旦停止了,你的app請求就沒發處理了。

如果你需要啟動後再執行的別的程序,可以使用多進程,把這個啟動放在別的進程里去執行。

如果解決了您的問題請採納!
如果未解決請繼續追問

④ python2.7怎麼實現非同步

改進之前
之前,我的查詢步驟很簡單,就是:
前端提交查詢請求 --> 建立資料庫連接 --> 新建游標 --> 執行命令 --> 接受結果 --> 關閉游標、連接
這幾大步驟的順序執行。
這裡面當然問題很大:
建立資料庫連接實際上就是新建一個套接字。這是進程間通信的幾種方法里,開銷最大的了。
在「執行命令」和「接受結果」兩個步驟中,線程在阻塞在資料庫內部的運行過程中,資料庫連接和游標都處於閑置狀態。
這樣一來,每一次查詢都要順序的新建資料庫連接,都要阻塞在資料庫返回結果的過程中。當前端提交大量查詢請求時,查詢效率肯定是很低的。
第一次改進
之前的模塊里,問題最大的就是第一步——建立資料庫連接套接字了。如果能夠一次性建立連接,之後查詢能夠反復服用這個連接就好了。
所以,首先應該把資料庫查詢模塊作為一個單獨的守護進程去執行,而前端app作為主進程響應用戶的點擊操作。那麼兩條進程怎麼傳遞消息呢?翻了幾天Python文檔,終於構思出來:用隊列queue作為生產者(web前端)向消費者(資料庫後端)傳遞任務的渠道。生產者,會與SQL命令一起,同時傳遞一個管道pipe的連接對象,作為任務完成後,回傳結果的渠道。確保,任務的接收方與發送方保持一致。
作為第二個問題的解決方法,可以使用線程池來並發獲取任務隊列中的task,然後執行命令並回傳結果。
第二次改進
第一次改進的效果還是很明顯的,不用任何測試手段。直接點擊頁面鏈接,可以很直觀地感覺到反應速度有很明顯的加快。
但是對於第二個問題,使用線程池還是有些欠妥當。因為,CPython解釋器存在GIL問題,所有線程實際上都在一個解釋器進程里調度。線程稍微開多一點,解釋器進程就會頻繁的切換線程,而線程切換的開銷也不小。線程多一點,甚至會出現「抖動」問題(也就是剛剛喚醒一個線程,就進入掛起狀態,剛剛換到棧幀或內存的上下文,又被換回內存或者磁碟),效率大大降低。也就是說,線程池的並發量很有限。
試過了多進程、多線程,只能在單個線程里做文章了。
Python中的asyncio庫
Python里有大量的協程庫可以實現單線程內的並發操作,比如Twisted、Gevent等等。Python官方在3.5版本里提供了asyncio庫同樣可以實現協程並發。asyncio庫大大降低了Python中協程的實現難度,就像定義普通函數那樣就可以了,只是要在def前面多加一個async關鍵詞。async def函數中,需要阻塞在其他async def函數的位置前面可以加上await關鍵詞。
import asyncio
async def wait():
await asyncio.sleep(2)
async def execute(task):
process_task(task)
await wait()
continue_job()
async def函數的執行稍微麻煩點。需要首先獲取一個loop對象,然後由這個對象代為執行async def函數。
loop = asyncio.get_event_loop()
loop.run_until_complete(execute(task))
loop.close()
loop在執行execute(task)函數時,如果遇到await關鍵字,就會暫時掛起當前協程,轉而去執行其他阻塞在await關鍵詞的協程,從而實現協程並發。
不過需要注意的是,run_until_complete()函數本身是一個阻塞函數。也就是說,當前線程會等候一個run_until_complete()函數執行完畢之後,才會繼續執行下一部函數。所以下面這段代碼並不能並發執行。
for task in task_list:
loop.run_until_complete(task)
對與這個問題,asyncio庫也有相應的解決方案:gather函數。
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函數的執行並不只有這兩種解決方案,還有call_soon與run_forever的配合執行等等,更多內容還請參考官方文檔。
Python下的I/O多路復用
協程,實際上,也存在上下文切換,只不過開銷很輕微。而I/O多路復用則完全不存在這個問題。
目前,linux上比較火的I/O多路復用API要算epoll了。Tornado,就是通過調用C語言封裝的epoll庫,成功解決了C10K問題(當然還有Pypy的功勞)。
在Linux里查文檔,可以看到epoll只有三類函數,調用起來比較方便易懂。
創建epoll對象,並返回其對應的文件描述符(file descriptor)。
int epoll_create(int size);
int epoll_create1(int flags);
控制監聽事件。第一個參數epfd就對應於前面命令創建的epoll對象的文件描述符;第二個參數表示該命令要執行的動作:監聽事件的新增、修改或者刪除;第三個參數,是要監聽的文件對應的描述符;第四個,代表要監聽的事件。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
等候。這是一個阻塞函數,調用者會等候內核通知所注冊的事件被觸發。
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()對應於第一類創建函數;
epoll.register(),epoll.unregister(),epoll.modify()均是對控制函數epoll_ctl的封裝;
epoll.poll()則是對等候函數epoll_wait的封裝。
Python里epoll相關API的最大問題應該是在epoll.poll()。相比於其所封裝的epoll_wait,用戶無法手動指定要等候的事件,也就是後者的第二個參數struct epoll_event *events。沒法實現精確控制。因此只能使用替代方案:select.select()函數。
根據Python官方文檔,select.select(rlist, wlist, xlist[, timeout])是對Unix系統中select函數的直接調用,與C語言API的傳參很接近。前三個參數都是列表,其中的元素都是要注冊到內核的文件描述符。如果想用自定義類,就要確保實現了fileno()方法。
其分別對應於:
rlist: 等候直到可讀
wlist: 等候直到可寫
xlist: 等候直到異常。這個異常的定義,要查看系統文檔。
select.select(),類似於epoll.poll(),先注冊文件和事件,然後保持等候內核通知,是阻塞函數。
實際應用
Psycopg2庫支持對非同步和協程,但和一般情況下的用法略有區別。普通資料庫連接支持不同線程中的不同游標並發查詢;而非同步連接則不支持不同游標的同時查詢。所以非同步連接的不同游標之間必須使用I/O復用方法來協調調度。
所以,我的大致實現思路是這樣的:首先並發執行大量協程,從任務隊列中提取任務,再向連接池請求連接,創建游標,然後執行命令,並返回結果。在獲取游標和接受查詢結果之前,均要阻塞等候內核通知連接可用。
其中,連接池返回連接時,會根據引用連接的協程數量,返回負載最輕的連接。這也是自己定義AsyncConnectionPool類的目的。
我的代碼位於:bottle-blog/dbservice.py
存在問題
當然了,這個流程目前還一些問題。
首先就是每次輪詢拿到任務之後,都會走這么一個流程。
獲取連接 --> 新建游標 --> 執行任務 --> 關閉游標 --> 取消連接引用
本來,最好的情況應該是:在輪詢之前,就建好游標;在輪詢時,直接等候內核通知,執行相應任務。這樣可以減少輪詢時的任務量。但是如果協程提前對應好連接,那就不能保證在獲取任務時,保持各連接負載均衡了。
所以這一塊,還有工作要做。
還有就是epoll沒能用上,有些遺憾。
以後打算寫點C語言的內容,或者用Python/C API,或者用Ctypes包裝共享庫,來實現epoll的調用。
最後,請允許我吐槽一下Python的epoll相關文檔:簡直太弱了!!!必須看源碼才能弄清楚功能。

⑤ Ppython await是什麼

await的解釋:

await用來聲明程序掛起。

比如非同步程序執行到某一步時需要等待的時間很長,就將此掛起,去執行其他的非同步程序。

await 後面只能跟非同步程序或有__await__屬性的對象,因為非同步程序與一般程序不同。

程序解釋:

假設有兩個非同步函數async a,async b,a中的某一步有await,

當程序碰到關鍵字await b()後,非同步程序掛起後去執行另一個非同步b程序,就是從函數內部跳出去執行其他函數,

當掛起條件消失後,不管b是否執行完,要馬上從b程序中跳出來,回到原程序執行原來的操作。

如果await後面跟的b函數不是非同步函數,那麼操作就只能等b執行完再返回,無法在b執行的過程中返回。

如果要在b執行完才返回,也就不需要用await關鍵字了,直接調用b函數就行。

所以這就需要await後面跟的是非同步函數了。

在一個非同步函數中,可以不止一次掛起,也就是可以用多個await。

更多Python知識,請關註:Python自學網!!

⑥ python協程和非同步IO——IO多路復用

C10k是一個在1999年被提出來的技術挑戰,如何在一顆1GHz CPU,2G內存,1gbps網路環境下,讓單台伺服器鏈滾同時為1萬個客戶端提供FTP服務

阻塞式I/O(使用最擾掘多)、非阻塞式I/O、I/O復用、信號驅動式I/O(幾乎不使用)、非同步I/O(POSIX的aio_系列函數)

select、poll、epoll都是IO多路復用的機制。I/O多路復用就是通過一種機制,一個進程可以監聽多個描述符,一旦,某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作。但select、poll、epoll本質上都是同步I/O,因為他們都需要在讀寫時間就緒後負責進行讀寫,也就是說讀寫過程是阻塞的,而非同步I/O無需自己負責進行讀寫,非同步I/O的實現會負責把數據從內核拷貝到用戶空間
(1)select
select函數監視的文件描述符分3類,分別是writefds、readfds、exceptfds。調用select函數會阻塞,直到有描述符就緒(有數據可讀、可寫或者有except),或者超時函數返回。當select函數返回後可以通過遍歷fdset來找到就緒的描述符。
select目前幾乎在所有的平台上支持,其良好的跨平台支持也是它的一個優點。select的一個缺點在於單個進程能夠監視的文件描述符的數量存在最大緩喚核限制,在Linux上一般為1024,可以通過修改宏定義甚至重新編譯內核的方式提升這一限制,但是這樣也會降低效率。
(2)poll
不同於select使用三個點陣圖來表示三個fdset的方式,poll使用一個pollfd的指針實現。
pollfd結構包含了要監視的event和發生的event,不再使用select"參數-值"傳遞的方式。同時pollfd並沒有最大數量限制(但是數量過大後性能也會下降)。和select函數一樣,poll返回後,需要輪詢pollfd來獲取就緒的描述符。
從上面看,select和poll都需要在返回後通過遍歷文件描述符來獲取已經就緒的socket。事實上同時連接的大量客戶端在同一時刻可能只有很少的處於就緒的狀態,因此隨著監視的描述符數量的增長,其效率也會線性下降
(3)epoll
epoll是在2.6內核中提出的,是之前的select和poll的增強版本。相對於select和poll來說,epoll更加領靈活,沒有描述符限制。epoll使用一個文件描述符管理多個描述符,將用戶關系的文件描述符的事件存放到內核的一個事件表中,這樣在用戶空間和內核空間的只需一次。

⑦ Python非同步編程全攻略

如果你厭倦了多線程,不妨試試python的非同步編程,再引入async, await關鍵字之後語法變得更加簡潔和直觀,又經過幾年的生態發展,現在是一個很不錯的並發模型。

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

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

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

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

本文所有依賴如下:

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

首先看一個錯誤的例子

輸出如下:

發現花費了3秒,不符合預期呀。。。。這是因為雖然用了協程,但是每個協程是串列的運行,也就是說後一個等前一個完成之後才開始,那麼這樣的非同步代碼並沒有並發,所以我們需要讓這些協程並行起來

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

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

如果我們不想要協程對象而是結果,那麼我們可以使用 asyncio.gather

結果輸出如下:

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

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

通過鎖讓並發慢下來,讓協程一個一個的運行。

輸出如下:

通過觀察很容易發現,並發的速度因為鎖而慢下來了,因為每次只有一個協程能獲得鎖,所以並發變成了串列。

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

輸出如下:

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

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

輸出如下:

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

通過創建協程的數量來控制並發並不是非常優雅的方式,所以可以通過信號量的方式來控制並發。

輸出如下:

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

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

有時候的並發需求是通過一個變數控制並發任務的並發數而不是通過創建協程的數量來控制並發,所以引入了信號量(Semaphore),這樣就可以在創建的協程數遠遠大於並發數的情況下讓協程在指定的並發量情況下並發。

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

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

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

輸出如下:

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

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

web框架

http客戶端

資料庫

ORM

雖然非同步庫發展得還算不錯,但是中肯的說並沒有覆蓋方方面面。

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

非同步編程雖然很不錯,不過,也許你並不需要。

⑧ Python非同步編程4:協程函數,協程對象,await關鍵字

協程函數:async def 函數名。3.5+

協程對象:執行協程函數()得到的協程蘆液御對象。

    3.5之後的寫法:

    3.7之後的寫法:更簡便

await後面 跟 可等待的對象。(協程對象,Future,Task對象 埋者約等於IO等待)

await實例2:串列執行。 一個協程函數裡面可以支持多個await ,雖然會串列,但是如果有其他協程函數,任務列表也在執行,依然會切換。只是案例中的main對陪岩應執行的others1和others2串列 。 await會等待對象的值得到之後才繼續往下走。

⑨ Python非同步編程7:非同步迭代器

迭代器:在其內部實現yield方法和next方法的對象。可迭代對象:在類內部實現一個iter方法,並返回一個迭代器。

非同步迭代器:實現了__aiter__()和__anext__()方法的對象,必須返回一個awaitable對象。async_for支持處理非同步迭代器的

__anext__()方法返回的可等待對象,直到引發一個stopAsyncIteration異常,這個改動由PEP 492引入。

非同步可迭代對象:可在async_for語句中被使用的對象,必須通過它的__aiter__()方法返回一個asynchronous_iterator(非同步迭代器).  這個改動由PEP 492引入。

示例: 不能直接寫在普通方法或者暴露在外面。必須寫在協程函數,任意協程函數均可。

⑩ python非同步有哪些方式

yield相當於return,他將相應的值返回給調用next()或者send()的調用者,從而交出了CPU使用權,而當調用者再次調用next()或者send()的時候,又會返回到yield中斷的地方,如果send有參數,還會將參數返回給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()041

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

yield from

使用yield from有兩個好處,

1、可以將main中send的參數一直返回給最里層的generator,
2、同時我們也不需要再使用while循環和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()

執行結果如下:

do something before coroutine start123456789101234567891011

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

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

import asyncio# Borrowed from http://curio.readthedocs.org/en/latest/[email protected] 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引入兩個重要概念協程和事件循環,
通過修飾符@asyncio.coroutine定義了一個協程,而通過event loop來執行tasks中所有的協程任務。之後在Python3.5引入了新的async & await語法,從而有了原生協程的概念。

async & await

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

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

#!/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("http://www.163.com"),
wait_download("http://www.mi.com"),
wait_download("http://www.google.com")])
end = time.time()
print("Complete in {} seconds".format(end - start))


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

這里會收到這樣的報錯:

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()函數返回的Response對象不能用於await表達式,可是如果不能用於await,還怎麼樣來實現非同步呢?
原來Python的await表達式是類似於」yield from」的東西,但是await會去做參數檢查,它要求await表達式中的對象必須是awaitable的,那啥是awaitable呢? awaitable對象必須滿足如下條件中其中之一:

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

原生協程對象

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

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

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

實現了await method,並在其中返回了iterator的對象

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

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


async def download(url): # 通過async def定義的函數是原生的協程對象
response = requests.get(url)
print(response.text)


async def wait_download(url):
await download(url) # 這里download(url)就是一個原生的協程對象
print("get {} data complete.".format(url))


async def main():
start = time.time()
await asyncio.wait([
wait_download("http://www.163.com"),
wait_download("http://www.mi.com"),
wait_download("http://www.google.com")])
end = time.time()
print("Complete in {} seconds".format(end - start))


loop = asyncio.get_event_loop()
loop.run_until_complete(main())27282930

好了現在一個真正的實現了非同步編程的小程序終於誕生了。
而目前更牛逼的非同步是使用uvloop或者pyuv,這兩個最新的Python庫都是libuv實現的,可以提供更加高效的event loop。

uvloop和pyuv

pyuv實現了Python2.x和3.x,但是該項目在github上已經許久沒有更新了,不知道是否還有人在維護。
uvloop只實現了3.x, 但是該項目在github上始終活躍。

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

import asyncioimport uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())123

與Python強制等待非同步函數相關的資料

熱點內容
墨痕齋是什麼游戲的伺服器 瀏覽:940
word文件如何壓縮大小 瀏覽:277
遵義聯通伺服器地址是什麼 瀏覽:29
ansys約束命令流 瀏覽:814
解壓軟體電腦版如何下載 瀏覽:791
閃電匕首演算法球 瀏覽:692
linuxredis停止命令 瀏覽:670
大麥賬號怎麼加密 瀏覽:113
穿越火線怎麼找伺服器 瀏覽:526
秘密加密社交軟體app 瀏覽:256
c語言編譯器怎麼找文件 瀏覽:835
數學不好能編程嗎 瀏覽:254
微雲里的視頻加密 瀏覽:41
3大加密貨幣交易平台 瀏覽:647
鈑金激光切割機編程 瀏覽:496
vivo手機手電筒app在哪裡 瀏覽:787
單片機晶振電路電容 瀏覽:887
穿越火線河南一區伺服器雲主機 瀏覽:41
文件夾與快捷方式顯示一致 瀏覽:879
幻影伺服器怎麼看金錢 瀏覽:349