Python中的異步:async?和?await以及操作中的事件循環(huán)、回調和異常
引言
在現(xiàn)代編程中,異步操作是一個非常重要的概念,尤其是在處理 I/O 密集型任務時。使用異步操作可以顯著提高程序的性能和響應速度。Python 提供了 async
和 await
關鍵字,使得編寫異步代碼變得更加直觀和簡潔。在這篇文章中,我們將深入探討 Python 的異步操作,并通過實際代碼示例來說明其使用方法。
什么是異步操作?
異步操作是一種非阻塞的編程方式,它允許程序在等待某個操作(如 I/O 操作)完成的同時繼續(xù)執(zhí)行其他任務。與同步操作不同,異步操作不會阻塞主線程,而是通過回調、事件循環(huán)等機制來實現(xiàn)并發(fā)處理。
Python 中的異步編程基礎
async
和 await
關鍵字
async
:定義一個異步函數(shù)。一個函數(shù)只需在def
前面加上async
關鍵字,就變成了異步函數(shù)。await
:等待一個異步操作的完成。只能在異步函數(shù)中使用。
asyncio
模塊
asyncio
是 Python 的標準庫模塊,提供了對異步 I/O、事件循環(huán)、任務調度等功能的支持。
import asyncio
理論與代碼示例
定義異步函數(shù)
首先,我們來定義一個簡單的異步函數(shù):
import asyncio async def say_hello(): print("Hello") await asyncio.sleep(1) # 模擬異步操作 print("World") # 異步函數(shù)不會立即執(zhí)行,需要在事件循環(huán)中運行
執(zhí)行異步函數(shù)
要運行異步函數(shù),需要在事件循環(huán)中調用它們。asyncio.run
是一種簡潔的方式來運行異步函數(shù)。
async def main(): await say_hello() # 使用 asyncio.run() 啟動事件循環(huán)并執(zhí)行異步函數(shù) if __name__ == "__main__": asyncio.run(main())
異步 I/O 操作示例
讓我們編寫一個更實際的示例,展示如何使用異步操作進行 I/O 密集型任務,如網(wǎng)絡請求。
import asyncio import aiohttp # 需要安裝 aiohttp 庫: pip install aiohttp async def fetch_url(session, url): async with session.get(url) as response: return await response.text() async def main(): urls = [ "https://www.example.com", "https://www.python.org", "https://www.asyncio.org" ] async with aiohttp.ClientSession() as session: tasks = [fetch_url(session, url) for url in urls] results = await asyncio.gather(*tasks) for url, content in zip(urls, results): print(f"URL: {url}, Content Length: {len(content)}") if __name__ == "__main__": asyncio.run(main())
在這個示例中:
fetch_url
:這是一個異步函數(shù),用于從指定的 URL 獲取內容。main
:在main
函數(shù)中,我們定義了一組 URL,并為每個 URL 創(chuàng)建一個異步任務。asyncio.gather
:該函數(shù)并發(fā)地運行所有任務,并等待它們全部完成。aiohttp.ClientSession
:這是一個異步 HTTP 客戶端會話,用于發(fā)送和接收 HTTP 請求。
高級用法:超時和取消任務
異步編程的一個重要優(yōu)勢是能夠設置超時和取消任務。我們可以使用 asyncio.wait_for
實現(xiàn)這一點。
import asyncio async def long_running_task(): await asyncio.sleep(10) return "Task completed" async def main(): try: result = await asyncio.wait_for(long_running_task(), timeout=5) print(result) except asyncio.TimeoutError: print("The task took too long and was cancelled.") if __name__ == "__main__": asyncio.run(main())
在這個示例中,如果 long_running_task
在 5 秒內沒有完成,則會拋出 asyncio.TimeoutError
異常。
異步編程的優(yōu)勢與局限性
優(yōu)勢
- 高效利用資源:異步編程可以在等待 I/O 操作完成時繼續(xù)執(zhí)行其他任務,從而更高效地利用 CPU 資源。
- 提高響應速度:對于 I/O 密集型任務,異步操作可以顯著提高程序的響應速度。
局限性
- 復雜性增加:異步編程相對于同步編程來說更加復雜,需要處理事件循環(huán)、回調和異常等。
- 調試困難:異步代碼的調試和錯誤追蹤相對較難。
事件循環(huán)、回調和異常
事件循環(huán)
理論解釋
事件循環(huán)是異步編程的核心,它不斷檢查和處理掛起的任務和 I/O 事件。Python 的 asyncio
模塊提供了對事件循環(huán)的支持。事件循環(huán)管理著所有異步任務的執(zhí)行,并在任務之間切換,從而實現(xiàn)并發(fā)。
具體代碼
import asyncio async def say_hello(): print("Hello") await asyncio.sleep(1) print("World") async def main(): # 獲取事件循環(huán) loop = asyncio.get_event_loop() # 創(chuàng)建任務 task = loop.create_task(say_hello()) # 運行任務 await task # 啟動事件循環(huán)并執(zhí)行主函數(shù) if __name__ == "__main__": asyncio.run(main())
在這個示例中,asyncio.get_event_loop()
獲取了當前的事件循環(huán),loop.create_task()
創(chuàng)建了一個任務并添加到事件循環(huán)中,await task
等待任務完成。
回調
理論解釋
回調函數(shù)是指在特定事件發(fā)生時自動調用的函數(shù)。在異步編程中,回調函數(shù)通常用于處理異步任務的結果或異常。asyncio
提供了多種方式來設置回調函數(shù),包括 Future
和 Task
對象的 add_done_callback
方法。
具體代碼
import asyncio async def slow_operation(): await asyncio.sleep(2) return "Operation Completed" def callback(future): print(future.result()) async def main(): loop = asyncio.get_event_loop() task = loop.create_task(slow_operation()) task.add_done_callback(callback) await task if __name__ == "__main__": asyncio.run(main())
在這個示例中,我們定義了一個名為 callback
的回調函數(shù),用于處理 slow_operation
異步任務的結果。task.add_done_callback(callback)
將回調函數(shù)與任務關聯(lián),一旦任務完成,回調函數(shù)將被自動調用并打印結果。
異常處理
理論解釋
在異步編程中,處理異常是至關重要的。任務在運行過程中可能會拋出異常,我們需要捕獲和處理這些異常,以確保程序的穩(wěn)定性。asyncio
提供了多種方式來處理異步任務中的異常。
具體代碼
import asyncio async def error_prone_operation(): await asyncio.sleep(1) raise ValueError("An error occurred") async def main(): try: await error_prone_operation() except ValueError as e: print(f"Caught an exception: {e}") if __name__ == "__main__": asyncio.run(main())
在這個示例中,error_prone_operation
異步函數(shù)在執(zhí)行過程中可能會拋出 ValueError
異常。在 main
函數(shù)中,我們使用 try...except
塊來捕獲和處理這個異常,確保程序不會因為未捕獲的異常而崩潰。
異步任務中的異常處理
除了直接在異步函數(shù)中捕獲異常外,我們還可以在任務完成后檢查異常。asyncio.Task
對象的 exception
方法可以用于檢查任務是否拋出了異常。
import asyncio async def error_prone_operation(): await asyncio.sleep(1) raise ValueError("An error occurred") async def main(): loop = asyncio.get_event_loop() task = loop.create_task(error_prone_operation()) try: await task except ValueError as e: print(f"Caught an exception: {e}") # 或者在任務完成后檢查異常 if task.exception(): print(f"Task raised an exception: {task.exception()}") if __name__ == "__main__": asyncio.run(main())
在這個示例中,我們首先在 try...except
塊中捕獲異常,然后在任務完成后通過 task.exception()
方法檢查任務是否拋出了異常。
超時處理
在某些情況下,異步操作可能需要設置超時,以避免長時間等待。asyncio.wait_for
函數(shù)可以用于設置異步操作的超時時間。
import asyncio async def long_running_task(): await asyncio.sleep(10) return "Task completed" async def main(): try: result = await asyncio.wait_for(long_running_task(), timeout=5) print(result) except asyncio.TimeoutError: print("The task took too long and was cancelled.") if __name__ == "__main__": asyncio.run(main())
在這個示例中,如果 long_running_task
在 5 秒內沒有完成,則會拋出 asyncio.TimeoutError
異常,我們可以捕獲并處理這個異常。
結論
異步編程是 Python 中處理并發(fā)和 I/O 密集型任務的一種強大工具。通過使用 async
和 await
關鍵字,以及 asyncio
模塊,我們可以編寫出高效且響應迅速的異步代碼。然而,異步編程也帶來了更高的復雜性,因此在使用時需要仔細權衡其優(yōu)勢和局限性。
通過了解事件循環(huán)、回調和異常處理,我們可以更好地掌握 Python 中的異步編程。事件循環(huán)是異步編程的核心,負責管理任務的調度和執(zhí)行;回調函數(shù)用于處理任務完成時的結果或異常;而異常處理則確保了程序的穩(wěn)定性和健壯性。
希望通過本文的詳細解釋和代碼示例,你能夠深入理解 Python 異步編程的底層原理和實際應用。在實際項目中,合理使用這些機制,可以顯著提高程序的性能和響應速度。
到此這篇關于Python中的異步:async 和 await以及操作中的事件循環(huán)、回調和異常的文章就介紹到這了,更多相關Python中的異步操作:async 和 await內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
python os.path.isfile()因參數(shù)問題判斷錯誤的解決
今天小編就為大家分享一篇python os.path.isfile()因參數(shù)問題判斷錯誤的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11springboot配置文件抽離 git管理統(tǒng) 配置中心詳解
在本篇文章里小編給大家整理的是關于springboot配置文件抽離 git管理統(tǒng) 配置中心的相關知識點內容,有需要的朋友們可以學習下。2019-09-09python使用matplotlib定制繪圖的線型、標記類型
這篇文章主要給大家詳細介紹了python使用matplotlib定制繪圖的線型、標記類型,文中有詳細的代碼示例,具有一定的參考價值,需要的朋友可以參考下2023-07-07利用python3 的pygame模塊實現(xiàn)塔防游戲
這篇文章主要介紹了利用python3 的pygame模塊實現(xiàn)塔防游戲,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-12-12PyTorch中torch.matmul()函數(shù)常見用法總結
torch.matmul()也是一種類似于矩陣相乘操作的tensor連乘操作。但是它可以利用python中的廣播機制,處理一些維度不同的tensor結構進行相乘操作,這篇文章主要介紹了PyTorch中torch.matmul()函數(shù)用法總結,需要的朋友可以參考下2023-04-04基于Python實現(xiàn)音樂播放器的實現(xiàn)示例代碼
這篇文章主要介紹了如何利用Python編寫簡易的音樂播放器,文中的示例代碼講解詳細,具有一的參考價值,需要的小伙伴可以參考一下2022-04-04