您好,登錄后才能下訂單哦!
這篇文章主要介紹Python中asyncio庫(kù)-線程并發(fā)函數(shù)的案例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
Asyncio ——gather vs wait
在Asyncio中不止可以多次使用asyncio.gather,還有另外一個(gè)用法是asyncio.wait,他們都可以讓多個(gè)協(xié)程并發(fā)執(zhí)行。
那為什么提供2個(gè)方法呢?他們有什么區(qū)別,適用場(chǎng)景是怎么樣的呢?我們先看2個(gè)協(xié)程的例子:
async def a(): print('Suspending a') await asyncio.sleep(3) print('Resuming a') return 'A' async def b(): print('Suspending b') await asyncio.sleep(1) print('Resuming b') return 'B'
在IPython里面用gather執(zhí)行一下:
In : return_value_a, return_value_b = await asyncio.gather(a(), b()) Suspending a Suspending b Resuming b Resuming a In : return_value_a, return_value_b Out: ('A', 'B')
Ok,asyncio.gather方法的名字說(shuō)明了它的用途,gather的意思是「搜集」,也就是能夠收集協(xié)程的結(jié)果,而且要注意,它會(huì)按輸入?yún)f(xié)程的順序保存的對(duì)應(yīng)協(xié)程的執(zhí)行結(jié)果。
接著我們說(shuō)asyncio.await,先執(zhí)行一下:
In : done, pending = await asyncio.wait([a(), b()]) Suspending b Suspending a Resuming b Resuming a In : done Out: {<Task finished coro=<a() done, defined at <ipython-input-5-5ee142734d16>:1> result='A'>, <Task finished coro=<b() done, defined at <ipython-input-5-5ee142734d16>:8> result='B'>} In : pending Out: set() In : task = list(done)[0] In : task Out: <Task finished coro=<b() done, defined at <ipython-input-5-5ee142734d16>:8> result='B'> In : task.result() Out: 'B'
asyncio.wait的返回值有2項(xiàng),第一項(xiàng)表示完成的任務(wù)列表(done),第二項(xiàng)表示等待(Future)完成的任務(wù)列表(pending),每個(gè)任務(wù)都是一個(gè)Task實(shí)例,由于這2個(gè)任務(wù)都已經(jīng)完成,所以可以執(zhí)行task.result()獲得協(xié)程返回值。
Ok, 說(shuō)到這里,總結(jié)下它倆的區(qū)別的第一層區(qū)別:
asyncio.gather封裝的Task全程黑盒,只告訴你協(xié)程結(jié)果。
asyncio.wait會(huì)返回封裝的Task(包含已完成和掛起的任務(wù)),如果你關(guān)注協(xié)程執(zhí)行結(jié)果你需要從對(duì)應(yīng)Task實(shí)例里面用result方法自己拿。
為什么說(shuō)「第一層區(qū)別」,asyncio.wait看名字可以理解為「等待」,所以返回值的第二項(xiàng)是pending列表,但是看上面的例子,pending是空集合,那么在什么情況下,pending里面不為空呢?這就是第二層區(qū)別:asyncio.wait支持選擇返回的時(shí)機(jī)。
asyncio.wait支持一個(gè)接收參數(shù)return_when,在默認(rèn)情況下,asyncio.wait會(huì)等待全部任務(wù)完成(return_when='ALL_COMPLETED'),它還支持FIRST_COMPLETED(第一個(gè)協(xié)程完成就返回)和FIRST_EXCEPTION(出現(xiàn)第一個(gè)異常就返回):
In : done, pending = await asyncio.wait([a(), b()], return_when=asyncio.tasks.FIRST_COMPLETED) Suspending a Suspending b Resuming b In : done Out: {<Task finished coro=<b() done, defined at <ipython-input-5-5ee142734d16>:8> result='B'>} In : pending Out: {<Task pending coro=<a() running at <ipython-input-5-5ee142734d16>:3> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x108065e58>()]>>}
看到了吧,這次只有協(xié)程b完成了,協(xié)程a還是pending狀態(tài)。
在大部分情況下,用asyncio.gather是足夠的,如果你有特殊需求,可以選擇asyncio.wait,舉2個(gè)例子:
需要拿到封裝好的Task,以便取消或者添加成功回調(diào)等
業(yè)務(wù)上需要FIRST_COMPLETED/FIRST_EXCEPTION即返回的
asyncio.create_task vs loop.create_task vs asyncio.ensure_future
創(chuàng)建一個(gè)Task一共有3種方法,如這小節(jié)的標(biāo)題。在上篇文章我說(shuō)過(guò),從Python 3.7開始可以統(tǒng)一的使用更高階的asyncio.create_task。其實(shí)asyncio.create_task就是用的loop.create_task:
def create_task(coro): loop = events.get_running_loop() return loop.create_task(coro)
loop.create_task接受的參數(shù)需要是一個(gè)協(xié)程,但是asyncio.ensure_future除了接受協(xié)程,還可以是Future對(duì)象或者awaitable對(duì)象:
如果參數(shù)是協(xié)程,其實(shí)底層還是用的loop.create_task,返回Task對(duì)象
如果是Future對(duì)象會(huì)直接返回
如果是一個(gè)awaitable對(duì)象會(huì)await這個(gè)對(duì)象的__await__方法,再執(zhí)行一次ensure_future,最后返回Task或者Future
所以就像ensure_future名字說(shuō)的,確保這個(gè)是一個(gè)Future對(duì)象:Task是Future 子類,前面說(shuō)過(guò)一般情況下開發(fā)者不需要自己創(chuàng)建Future
其實(shí)前面說(shuō)的asyncio.wait和asyncio.gather里面都用了asyncio.ensure_future。對(duì)于絕大多數(shù)場(chǎng)景要并發(fā)執(zhí)行的是協(xié)程,所以直接用asyncio.create_task就足夠了~
以上是Python中asyncio庫(kù)-線程并發(fā)函數(shù)的案例分析的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。