概述
很多時候我們使用python的異步,其實並不關心他的發展和演化,只想知道原理和怎麼使用的。
原理
其實協程就是基於cpu寄存器級的上下文切換,而線程是基於內存級切換。協程的切換速度和效率遠高於線程,所以爲python的大併發提供了基礎。
像線程一樣使用協程
任務
線程裏面有主線程和子線程的概念,在協程裏面對應爲主任務和子任務。
同樣的,如果主任務結束,子任務也會自動結束,在線程裏面可以等待子線程完成,同樣的,在協程也可以。
import asyncio
async def coro():
print("start")
await asyncio.sleep(1)
print("wait cancel")
await asyncio.sleep(5)
print("cancel fail")
async def t():
task = asyncio.create_task(coro(),name="coro111")#創建一個協程任務,與主任務並行運行
print("get_task:",task)
await asyncio.sleep(3)
# task.cancel()
x=asyncio.all_tasks()
for k in x:
if k.get_name()=="coro111":
if not k.cancelled():
k.cancel()
# for k in x:
# if k.get_name()=="coro111":
# if k.cancelled():
# k.r
await asyncio.sleep(5)
x = asyncio.all_tasks()
for k in x:
print(k.get_name())
print(x)
if __name__ == '__main__':
loop=asyncio.get_event_loop()
loop.create_task(t())#創建一個協程任務
loop.run_forever()#所有任務都執行
# asyncio.run(t())#等待主任務執行完畢
asyncio.create_task
會得到一個任務Task,其對應的主要有如下方法:
Task 對象
class asyncio.Task(coro, *, loop=None, name=None)#一個與 Future 類似 的對象,可運行 Python 協程。非線程安全。Task 對象被用來在事件循環中運行協程。如果一個協程在等待一個 Future 對象,Task 對象會掛起該協程的執行並等待該 Future 對象完成。當該 Future 對象 完成,被打包的協程將恢復執行。
#使用高層級的 asyncio.create_task() 函數來創建 Task 對象
cancelled() #可被用來檢測 Task 對象是否被取消。如果打包的協程沒有抑制 CancelledError 異常並且確實被取消,該方法將返回 True。
#Task 對象支持 contextvars 模塊。當一個 Task 對象被創建,它將複製當前上下文,然後在複製的上下文中運行其協程。
cancel()#請求取消 Task 對象。這將安排在下一輪事件循環中拋出一個 CancelledError 異常給被封包的協程。
cancelled()#如果 Task 對象 被取消 則返回 True。
done()#如果 Task 對象 已完成 則返回 True。當 Task 所封包的協程返回一個值、引發一個異常或 Task 本身被取消時,則會被認爲 已完成。
result()#返回 Task 的結果。
#如果 Task 對象 已完成,其封包的協程的結果會被返回 (或者當協程引發異常時,該異常會被重新引發。)
#如果 Task 對象 被取消,此方法會引發一個 CancelledError 異常。
#如果 Task 對象的結果還不可用,此方法會引發一個 InvalidStateError 異常。
exception()#返回 Task 對象的異常。
add_done_callback(callback, *, context=None)#添加一個回調,將在 Task 對象 完成 時被運行。
remove_done_callback(callback)#從回調列表中移除 callback 。
get_stack(*, limit=None)#返回此 Task 對象的棧框架列表。
print_stack(*, limit=None, file=None)#打印此 Task 對象的棧或回溯。
get_coro()
返回由 Task 包裝的協程對象。
get_name()#返回 Task 的名稱。
set_name(value)#設置 Task 的名稱。value 參數可以爲任意對象,它隨後會被轉換爲字符串。在默認的 Task 實現中,名稱將在任務對象的 repr() 輸出中可見。
示例:
async def cancel_me():
print('cancel_me(): before sleep')
try:
# Wait for 1 hour
await asyncio.sleep(3600)
except asyncio.CancelledError:
print('cancel_me(): cancel sleep')
raise
finally:
print('cancel_me(): after sleep')
async def main():
# Create a "cancel_me" Task
task = asyncio.create_task(cancel_me())
# Wait for 1 second
await asyncio.sleep(1)
task.cancel()
try:
await task
except asyncio.CancelledError:
print("main(): cancel_me is cancelled now")
asyncio.run(main())