導語:本文記錄了我學習Python基本控制流的關鍵知識和個人經驗,有意入門Python的朋友可以前來壹起學習交流。
這篇文章的重點是:
1,了解asyncio包的功能和用法;
2.了解如何避免阻塞呼叫;
3、學會利用過程,避免喚回地獄。
首先,使用asyncio包進行並發編程。
1,並發和並行
並發性:同時處理多件事情。
並行:同時做很多事情。
並發用於制定計劃和解決可能(但不壹定)的並行問題。並發更好。
2.asyncio概述
了解asyncio的四個特征:
Asyncio包使用事件周期驅動的協程實現並發。
適用於asyncio API的流程必須在定義體中使用yield from,而不是yield。
asyncio處理的流程需要在定義體上用@asyncio.coroutine修飾。裝修的作用是突出協同,當協同沒有產生價值時,協同就會被垃圾回收。
從Python3.4開始,asyncio包只直接支持TCP和UDP協議。如果要用asyncio實現HTTP客戶端和服務器,經常會用到aiople()。也就是說,協程不是通過調用next()函數或。send()方法。
書面協同鏈最終通過yield from將責任委托給asyncio包中的協同功能或方法。也就是最裏面的子生成器是實際在庫中執行I/O操作的函數,而不是我們自己寫的函數。
例——通過asyncio包和協程以動畫形式顯示文本旋轉指針;
進口異步
導入itertools
導入系統
@asyncio.coroutine #交給asyncio的談判過程要用@asyncio.coroutine來修飾。
定義旋轉(消息):
對於itertools.cycle中的char(' |/-\ '):
狀態=字符+ ' ' +消息
打印(狀態)
嘗試:
asyncio的產量。sleep (.1) #使用asyncio的產量。sleep (.1)而不是time.sleep(.1),這樣不會阻塞事件循環。
除了阿辛西奧。CancelledError: #如果spin函數喚醒並拋出壹個asyncio。cancelederror異常,原因是發出了取消請求,所以退出循環。
破裂
@asyncio.coroutine
def slow _ function():# slow _ function函數是壹個協程。假裝在休眠狀態下執行I/O操作時,使用yield from繼續執行事件循環。
#假裝等待I/O壹會兒
表達式yield from asyncio。睡眠(3) #從焦慮中屈服。sleep (3)將控制權交給主循環,並在休眠後繼續這個過程。
返回42
@asyncio.coroutine
Def supervisor(): # supervisor函數也是壹個協程。
spinner = async io . async(spin(' thinking!'))# asyncio.async(...)函數調度自旋協程的運行時間,用任務對象包裝自旋協程,並立即返回。
打印(' spinner對象:',spinner)
result = yield from slow_function()#驅動slow _ function()函數。完成後,獲取返回值。
#同時,事件循環繼續運行,因為slow_function函數最終使用表達式yield from asyncio.sleep(3)將控制返回到主循環。
可以取消spinner.cancel() #任務對象;取消後,asyncio。CancelledError異常將在進程當前掛起的yield處引發。流程可以捕捉這個異常,延遲取消,甚至拒絕取消。
回送結果
if name == 'main ':
Loop = asyncio.get_event_loop() #獲取事件循環的引用。
結果=循環。run _ until _ complete(supervisor())#驅動管理器完成運行;這個過程的返回值就是這個調用的返回值。
loop.close()
打印('答案:',結果)3。線程和協程的比較。
線程:調度程序可以在任何時候中斷線程。妳必須記得鎖好。保護程序的重要部分,防止多步操作在執行過程中被中斷,防止數據處於無效狀態。
協調:默認情況下,它將被完全保護,以防止中斷。沒有必要為協程保持鎖定。如果在多個線程之間同步操作,協程本身也會同步,因為任何時候只有壹個協程運行。
4、從周期、任務和進度上輸出。
在asyncio程序包中,期間和流程密切相關,因為您可以使用yield from從asyncio生成結果。未來對象。這意味著如果foo是壹個並發函數或者是壹個返回Future或Task實例的普通函數,可以寫成如下形式:res=yield from foo()。這也是asyncio包裏很多地方可以交換合同和條款的原因之壹。
第二,避免阻止通話
1,有兩種方法可以避免阻塞調用來停止整個應用程序進程:
在單獨的線程中運行每個阻塞操作。
將每個阻塞操作轉換成壹個非阻塞異步調用。
使用多線程處理大量連接會消耗太多內存,所以通常使用回調來實現異步調用。
2.使用Executor對象防止阻塞事件循環:
使用loop.run_in_executor將阻塞的作業(如保存文件)委托給線程池。
@asyncio.coroutine
def download_one(cc,base_url,信號量,verbose):
嘗試:
用(信號量的產量):
image = get _ flag(base _ URL,cc)的yield
除了web。HTTPNotFound:
status = HTTPStatus.not_found
消息= '未找到'
例外情況除外:
從exc中取出FetchError(cc)
否則:
Loop = asyncio.get_event_loop() #獲取事件循環對象的引用。
Loop.run _ in _ executor (none,# none使用TrreadPoolExecutor的默認實例。
Save _ flag,image,cc.lower ()+'。gif') #傳入壹個可調用對象。
status = HTTPStatus.ok
msg = 'OK '
如果詳細和消息:
打印(抄送,郵件)
ThreadPoolExecutor對象在返回結果(status,cc)asyncio的事件循環之後維護。我們可以調用run_in_executor方法,將可調用對象發送給它執行。
第三,從回調到到期和協商
回調地獄:如果壹個操作需要依賴之前操作的結果,它必須嵌套回調。
Python中的回調地獄:
定義階段1(響應1):
請求2 =步驟1(響應1)
api_call2(請求2,階段2)
定義階段2(響應2):
請求3 =步驟2(響應2)
api_call3(請求3,階段3)
定義階段3(響應3):
步驟3(響應3)
API _ Call1(請求1,步驟1)使用協程和yield from結構進行異步編程,無需回調:
@asyncio.coroutine
定義三個階段(請求1):
response1 =來自api_call1()的產量
請求2 =步驟1(響應1)
response2 =來自api_call2(請求2)的產量
請求3 =步驟2(響應2)
response3 =來自api_call3(請求3)的產量
步驟3(響應3)
loop.create_task(三個階段(請求1))
#協程不能直接調用,指定協程的執行時間必須按事件周期顯示,也可以在其他有調度執行時間的協程中使用yield from expression激活。
使用asyncio包可以實現TCP和HTTP服務器。
Web服務將成為asyncio包的壹個重要使用場景。
相信看完這個案例,妳已經掌握了方法。更多精彩請關註Gxl上其他相關文章!
推薦閱讀:
如何將python字符串轉換成二維數組
如何用Vue導出excel表格函數