Python中的asyncio庫-shield函數(shù)?針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。
創(chuàng)新互聯(lián)公司長期為成百上千家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為伊通企業(yè)提供專業(yè)的成都做網(wǎng)站、成都網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè),伊通網(wǎng)站改版等技術(shù)服務(wù)。擁有10多年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。
shield
asyncio.shield,用它可以屏蔽取消操作。一直到這里,我們還沒有見識過Task的取消??匆粋€(gè)例子:
In : loop = asyncio.get_event_loop() In : task1 = loop.create_task(a()) In : task2 = loop.create_task(b()) In : task1.cancel() Out: True In : await asyncio.gather(task1, task2) Suspending a Suspending b --------------------------------------------------------------------------- CancelledError Traceback (most recent call last) cell_name in async-def-wrapper() CancelledError:
在上面的例子中,task1被取消了后再用asyncio.gather收集結(jié)果,直接拋CancelledError錯(cuò)誤了。這里有個(gè)細(xì)節(jié),gather支持return_exceptions參數(shù):
In : await asyncio.gather(task1, task2, return_exceptions=True) Out: [concurrent.futures._base.CancelledError(), 'B']
可以看到,task2依然會執(zhí)行完成,但是task1的返回值是一個(gè)CancelledError錯(cuò)誤,也就是任務(wù)被取消了。如果一個(gè)創(chuàng)建后就不希望被任何情況取消,可以使用asyncio.shield保護(hù)任務(wù)能順利完成。不過要注意一個(gè)陷阱,先看錯(cuò)誤的寫法:
In : task1 = asyncio.shield(a()) In : task2 = loop.create_task(b()) In : task1.cancel() Out: True In : await asyncio.gather(task1, task2, return_exceptions=True) Suspending a Suspending b Resuming b Out: [concurrent.futures._base.CancelledError(), 'B']
可以看到依然是CancelledError錯(cuò)誤,且協(xié)程a未執(zhí)行完成,正確的用法是這樣的:
In : task1 = asyncio.shield(a()) In : task2 = loop.create_task(b()) In : ts = asyncio.gather(task1, task2, return_exceptions=True) In : task1.cancel() Out: True In : await ts Suspending a Suspending b Resuming a Resuming b Out: [concurrent.futures._base.CancelledError(), 'B']
可以看到雖然結(jié)果是一個(gè)CancelledError錯(cuò)誤,但是看輸出能確認(rèn)協(xié)程實(shí)際上是執(zhí)行了的。所以正確步驟是:
先創(chuàng)建 GatheringFuture 對象 ts
取消任務(wù)
await ts
asynccontextmanager
如果你了解Python,之前可能聽過或者用過contextmanager ,一個(gè)上下文管理器。通過一個(gè)計(jì)時(shí)的例子就理解它的作用:
from contextlib import contextmanager async def a(): await asyncio.sleep(3) return 'A' async def b(): await asyncio.sleep(1) return 'B' async def s1(): return await asyncio.gather(a(), b()) @contextmanager def timed(func): start = time.perf_counter() yield asyncio.run(func()) print(f'Cost: {time.perf_counter() - start}')
timed函數(shù)用了contextmanager裝飾器,把協(xié)程的運(yùn)行結(jié)果yield出來,執(zhí)行結(jié)束后還計(jì)算了耗時(shí):
In : from contextmanager import * In : with timed(s1) as rv: ...: print(f'Result: {rv}') ...: Result: ['A', 'B'] Cost: 3.0052654459999992
大家先體會一下。在Python 3.7添加了asynccontextmanager,也就是異步版本的contextmanager,適合異步函數(shù)的執(zhí)行,上例可以這么改:
@asynccontextmanager async def async_timed(func): start = time.perf_counter() yield await func() print(f'Cost: {time.perf_counter() - start}') async def main(): async with async_timed(s1) as rv: print(f'Result: {rv}') In : asyncio.run(main()) Result: ['A', 'B'] Cost: 3.00414147500004
async版本的with要用async with,另外要注意yield await func()這句,相當(dāng)于yield + await func()
PS: contextmanager 和 asynccontextmanager 最好的理解方法是去看源碼注釋
關(guān)于Python中的asyncio庫-shield函數(shù)問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。