Python使用asyncio包實(shí)現(xiàn)異步編程方式
1. 異步編程
異步編程是一種編程范式,用于處理程序中需要等待異步操作完成后才能繼續(xù)執(zhí)行的情況。
異步編程允許程序在執(zhí)行耗時(shí)的操作時(shí)不被阻塞,而是在等待操作完成時(shí)繼續(xù)執(zhí)行其他任務(wù)。
這對于處理諸如文件 I/O、網(wǎng)絡(luò)請求、定時(shí)器等需要等待的操作非常有用。
使用異步編程通??梢詭硪韵潞锰帲?/p>
- 提高程序效率和性能:異步編程使得程序在執(zhí)行耗時(shí)的 I/O 操作(如網(wǎng)絡(luò)請求、文件讀寫、數(shù)據(jù)庫查詢等)時(shí)不會被阻塞,減少了等待時(shí)間,充分利用了系統(tǒng)資源。
- 改善用戶體驗(yàn):在 Web 開發(fā)中,異步編程可以確保服務(wù)器在處理大量并發(fā)請求時(shí)能夠快速地響應(yīng)用戶,從而提高了 Web 應(yīng)用的響應(yīng)速度和用戶體驗(yàn)。
2 async/await和asyncio包
2.1 異步函數(shù)的定義
在Python中實(shí)現(xiàn)異步函數(shù)的定義需要兩個關(guān)鍵字(async
和await
)。
async
:async
關(guān)鍵字聲明一個異步函數(shù)。它可以在執(zhí)行過程中暫停并允許其他代碼執(zhí)行。當(dāng)你調(diào)用一個異步函數(shù)時(shí),它會立即返回一個協(xié)程對象而不是實(shí)際的結(jié)果。異步函數(shù)適用于執(zhí)行耗時(shí)的I/O操作,例如網(wǎng)絡(luò)請求、文件讀寫、數(shù)據(jù)庫查詢等。這些操作通常涉及到等待外部資源的響應(yīng)或者數(shù)據(jù)的傳輸,而在等待的過程中,CPU可以執(zhí)行其他任務(wù),從而提高程序的效率。await
:await
關(guān)鍵字在Python中用于等待一個異步操作完成。當(dāng)調(diào)用異步函數(shù)時(shí),使用await
關(guān)鍵字可以暫時(shí)掛起當(dāng)前的異步函數(shù)的執(zhí)行,將CPU控制權(quán)還給事件循環(huán)(Event Loop)。接著事件循環(huán)可以將執(zhí)行權(quán)轉(zhuǎn)移到其他任務(wù)上,而不是一直等待當(dāng)前的異步函數(shù)完成。當(dāng)被await
的異步操作完成后,事件循環(huán)會通知原來的異步函數(shù),使得它可以繼續(xù)執(zhí)行后續(xù)的操作。
在Python中異步函數(shù)的定義需要同時(shí)滿足以下兩個條件:
- 使用
async def
關(guān)鍵字聲明函數(shù)。 - 函數(shù)內(nèi)部包含異步操作,并且使用了
await
關(guān)鍵字等待異步操作完成。如果一個函數(shù)中只使用了async def
聲明,但其中任何異步操作,也沒有使用await
關(guān)鍵字,那么它實(shí)際上就是一個普通的同步函數(shù),而不是一個異步函數(shù)。
2.2 事件循環(huán)
事件循環(huán)(Event Loop)是異步編程中負(fù)責(zé)管理和調(diào)度異步任務(wù)執(zhí)行的機(jī)制。
事件循環(huán)的工作原理類似于一個持續(xù)運(yùn)行的循環(huán),它在每一輪循環(huán)中都會執(zhí)行以下幾個步驟:
- 等待任務(wù)就緒: 事件循環(huán)會等待所有注冊的異步任務(wù)就緒,包括等待 I/O 操作完成、等待計(jì)時(shí)器超時(shí)等。
- 選擇就緒任務(wù):一旦有任務(wù)就緒,事件循環(huán)會選擇其中一個任務(wù)進(jìn)行執(zhí)行。
- 執(zhí)行任務(wù):事件循環(huán)會執(zhí)行所選擇的就緒任務(wù),直到任務(wù)完成或者遇到
await
關(guān)鍵字,需要暫時(shí)掛起任務(wù)的執(zhí)行。 - 掛起任務(wù):如果任務(wù)遇到
await
關(guān)鍵字,它會將控制權(quán)交還給事件循環(huán),并等待await
后面的異步操作完成。 - 繼續(xù)執(zhí)行其他任務(wù):在等待
await
的異步操作完成的過程中,事件循環(huán)會繼續(xù)執(zhí)行其他就緒的任務(wù),從而實(shí)現(xiàn)了并發(fā)執(zhí)行的效果。 - 異步操作完成: 當(dāng)一個 await 后面的異步操作完成后,事件循環(huán)會通知原來的任務(wù),使得它可以繼續(xù)執(zhí)行后續(xù)的操作。
2.2 asyncio包
asyncio
包python中常用的異步編程框架,這里使用該框架完成一個簡單的異步編程案例,具體如下:
import time import datetime import asyncio async def async_read_file(): print("async讀文件開始:",datetime.datetime.fromtimestamp(time.time())) await asyncio.sleep(20) print("async讀文件完成:",datetime.datetime.fromtimestamp(time.time())) def computer(): print("普通計(jì)算密集型任務(wù):",datetime.datetime.fromtimestamp(time.time())) sum=0 for i in range(1000000): if i%250000==0 and i!=0: print("普通計(jì)算密集型任務(wù)正在執(zhí)行:",datetime.datetime.fromtimestamp(time.time())) for j in range(500): sum+=i+j-2*j print("普通計(jì)算密集型任務(wù)完成:",datetime.datetime.fromtimestamp(time.time())) def computer2(): print("普通CPU密集型任務(wù):",datetime.datetime.fromtimestamp(time.time())) sum=0 for i in range(1000000): if i%250000==0 and i!=0: print("普通CPU密集型任務(wù)正在執(zhí)行:",datetime.datetime.fromtimestamp(time.time())) for j in range(5000): sum+=i+j-2*j print("普通CPU密集型任務(wù)完成:",datetime.datetime.fromtimestamp(time.time())) async def asy_main(): task=loop.create_task(async_read_file()) # 創(chuàng)建一個任務(wù),并添加到事件循環(huán),等待執(zhí)行 task2=loop.run_in_executor(None,computer)# 將普通函數(shù)read_file添加到事件循環(huán)中,等待執(zhí)行 task3=loop.run_in_executor(None,computer2)# 將普通函數(shù)read_file2添加到事件循環(huán)中,等待執(zhí)行 await task3 await task2 await task loop=asyncio.get_event_loop() # 創(chuàng)建一個事件循環(huán) loop.run_until_complete(asy_main())
其執(zhí)行結(jié)果如下:
普通計(jì)算密集型任務(wù): 2024-05-15 18:29:19.702689
普通CPU密集型任務(wù): 2024-05-15 18:29:19.708280
async讀文件開始: 2024-05-15 18:29:19.738654
普通計(jì)算密集型任務(wù)正在執(zhí)行: 2024-05-15 18:29:21.441072
普通計(jì)算密集型任務(wù)正在執(zhí)行: 2024-05-15 18:29:23.192585
普通計(jì)算密集型任務(wù)正在執(zhí)行: 2024-05-15 18:29:24.936979
普通計(jì)算密集型任務(wù)完成: 2024-05-15 18:29:26.712930
普通CPU密集型任務(wù)正在執(zhí)行: 2024-05-15 18:29:32.539679
async讀文件完成: 2024-05-15 18:29:39.752731
普通CPU密集型任務(wù)正在執(zhí)行: 2024-05-15 18:29:41.813872
普通CPU密集型任務(wù)正在執(zhí)行: 2024-05-15 18:29:51.103737
普通CPU密集型任務(wù)完成: 2024-05-15 18:30:00.433402
從代碼運(yùn)行結(jié)果中可以看到,兩個計(jì)算密集型的任務(wù)task2、task3和異步函數(shù)task添加到事件循環(huán)上之后,在等待異步操作task完成的過程中,CPU并沒有閑著,而是在執(zhí)行task2和task3的任務(wù)。
Tips:雖然當(dāng)下的執(zhí)行結(jié)果中寫完成了computer()的計(jì)算,后完成了computer2()的計(jì)算,但多次執(zhí)行上述程序的時(shí)候也出現(xiàn)了兩個函數(shù)交替執(zhí)行的結(jié)果。
為了與上述代碼形成對比,執(zhí)行下述代碼:
import asyncio import datetime async def async_task(name, delay): print(f"Task {name} started:",datetime.datetime.now()) await asyncio.sleep(delay) print(f"Task {name} finished:",datetime.datetime.now()) async def main(): await async_task("A", 2) await async_task("B", 1) await async_task("C", 3) asyncio.run(main())
其代碼執(zhí)行結(jié)果如下:
Task A started: 2024-05-21 17:45:24.324535
Task A finished: 2024-05-21 17:45:26.326109
Task B started: 2024-05-21 17:45:26.326250
Task B finished: 2024-05-21 17:45:27.327795
Task C started: 2024-05-21 17:45:27.327923
Task C finished: 2024-05-21 17:45:30.329475
從執(zhí)行結(jié)果上可以看到這三個異步操作是順序執(zhí)行的,并沒有同時(shí)執(zhí)行。
這是因?yàn)樵趫?zhí)行await
后面的異步操作時(shí)事件循環(huán)中只有一個任務(wù)。
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
- Python使用asyncio實(shí)現(xiàn)異步操作的示例
- Python中asyncio的多種用法舉例(異步同步)
- Python使用asyncio處理異步編程的代碼示例
- Python異步庫asyncio、aiohttp詳解
- python協(xié)程異步IO中asyncio的使用
- Python使用asyncio標(biāo)準(zhǔn)庫對異步IO的支持
- Python協(xié)程異步爬取數(shù)據(jù)(asyncio+aiohttp)實(shí)例
- Python使用asyncio異步時(shí)的常見問題總結(jié)
- Python asyncio異步編程常見問題小結(jié)
- Python asyncio異步編程簡單實(shí)現(xiàn)示例
- Python中asyncio庫實(shí)現(xiàn)異步編程的示例
相關(guān)文章
Python保留指定位數(shù)小數(shù)的5種方法總結(jié)
很多小伙伴在學(xué)習(xí)python的時(shí)候可能會遇到對數(shù)據(jù)進(jìn)行格式化輸出的需求,其中最常見的需求為保留幾位小數(shù),這篇文章主要給大家介紹了關(guān)于Python保留指定位數(shù)小數(shù)的5種方法,需要的朋友可以參考下2023-08-08python tkinter GUI繪制,以及點(diǎn)擊更新顯示圖片代碼
這篇文章主要介紹了python tkinter GUI繪制,以及點(diǎn)擊更新顯示圖片代碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03Flask框架利用Echarts實(shí)現(xiàn)繪制圖形
echarts是百度推出的一款開源的基于JavaScript的可視化圖表庫,該開發(fā)庫目前發(fā)展非常不錯,且支持各類圖形的繪制可定制程度高。如下演示案例中,將分別展示運(yùn)用該繪圖庫如何前后端交互繪制(餅狀圖,柱狀圖,折線圖)這三種最基本的圖形,需要的可以參考一下2022-10-10Python使用Flask框架同時(shí)上傳多個文件的方法
這篇文章主要介紹了Python使用Flask框架同時(shí)上傳多個文件的方法,實(shí)例分析了Python中Flask框架操作文件實(shí)現(xiàn)上傳的技巧,需要的朋友可以參考下2015-03-03使用Python設(shè)置tmpfs來加速項(xiàng)目的教程
這篇文章主要介紹了使用Python設(shè)置tmpfs來加速項(xiàng)目的教程,文中給出方法使用Python腳本將tmpfs保存于內(nèi)存中的程序存儲到本地硬盤上,需要的朋友可以參考下2015-04-04卸載tensorflow-cpu重裝tensorflow-gpu操作
這篇文章主要介紹了卸載tensorflow-cpu重裝tensorflow-gpu操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06Python+matplotlib實(shí)現(xiàn)堆疊圖的繪制
Matplotlib作為Python的2D繪圖庫,它以各種硬拷貝格式和跨平臺的交互式環(huán)境生成出版質(zhì)量級別的圖形。本文將利用Matplotlib庫繪制堆疊圖,感興趣的可以了解一下2022-03-03