欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

asyncio 的 coroutine對(duì)象 與 Future對(duì)象使用指南

 更新時(shí)間:2016年09月11日 10:00:26   投稿:hebedich  
asyncio是Python 3.4版本引入的標(biāo)準(zhǔn)庫,直接內(nèi)置了對(duì)異步IO的支持。asyncio的編程模型就是一個(gè)消息循環(huán)。今天我們就來詳細(xì)討論下asyncio 中的 coroutine 與 Future對(duì)象

coroutine 與 Future 的關(guān)系

看起來兩者是一樣的,因?yàn)槎伎梢杂靡韵碌恼Z法來異步獲取結(jié)果,

result = await future
result = await coroutine

實(shí)際上,coroutine 是生成器函數(shù),它既可以從外部接受參數(shù),也可以產(chǎn)生結(jié)果。使用 coroutine 的好處是,我們可以暫停一個(gè)函數(shù),然后稍后恢復(fù)執(zhí)行。比如在涉及到網(wǎng)路操作的情況下,能夠停下函數(shù)直到響應(yīng)到來。在停下的這段時(shí)間內(nèi),我們可以切換到其他任務(wù)繼續(xù)執(zhí)行。

而 Future 更像是 Javascript 中的 Promise 對(duì)象。它是一個(gè)占位符,其值會(huì)在將來被計(jì)算出來。在上述的例子中,當(dāng)我們?cè)诘却W(wǎng)絡(luò) IO 函數(shù)完成時(shí),函數(shù)會(huì)給我們一個(gè)容器,Promise 會(huì)在完成時(shí)填充該容器。填充完畢后,我們可以用回調(diào)函數(shù)來獲取實(shí)際結(jié)果。

Task 對(duì)象是 Future 的子類,它將 coroutine 和 Future 聯(lián)系在一起,將 coroutine 封裝成一個(gè) Future 對(duì)象。

一般會(huì)看到兩種任務(wù)啟動(dòng)方法,

tasks = asyncio.gather(
  asyncio.ensure_future(func1()),
  asyncio.ensure_future(func2())
)
loop.run_until_complete(tasks)


tasks = [
  asyncio.ensure_future(func1()),
  asyncio.ensure_future(func2())
  ]
loop.run_until_complete(asyncio.wait(tasks))

ensure_future 可以將 coroutine 封裝成 Task。asyncio.gather 將一些 Future 和 coroutine 封裝成一個(gè) Future。

asyncio.wait 則本身就是 coroutine。

run_until_complete 既可以接收 Future 對(duì)象,也可以是 coroutine 對(duì)象,

BaseEventLoop.run_until_complete(future)

Run until the Future is done.
If the argument is a coroutine object, it is wrapped by ensure_future().
Return the Future's result, or raise its exception.

Task 任務(wù)的正確退出方式

在 asyncio 的任務(wù)循環(huán)中,如果使用 CTRL-C 退出的話,即使捕獲了異常,Event Loop 中的任務(wù)會(huì)報(bào)錯(cuò),出現(xiàn)如下的錯(cuò)誤,

Task was destroyed but it is pending!
task: <Task pending coro=<kill_me() done, defined at test.py:5> wait_for=<Future pending cb=[Task._wakeup()]>>

根據(jù)官方文檔,Task 對(duì)象只有在以下幾種情況,會(huì)認(rèn)為是退出,

a result / exception are available, or that the future was cancelled

Task 對(duì)象的 cancel 和其父類 Future 略有不同。當(dāng)調(diào)用 Task.cancel() 后,對(duì)應(yīng) coroutine 會(huì)在事件循環(huán)的下一輪中拋出 CancelledError 異常。使用 Future.cancelled() 并不能立即返回 True(用來表示任務(wù)結(jié)束),只有在上述異常被處理任務(wù)結(jié)束后才算是 cancelled。

故結(jié)束任務(wù)可以用

for task in asyncio.Task.all_tasks():
  task.cancel()

這種方法將所有任務(wù)找出并 cancel。

但 CTRL-C 也會(huì)將事件循環(huán)停止,所以有必要重啟事件循環(huán),

try:
  loop.run_until_complete(tasks)
except KeyboardInterrupt as e:
  for task in asyncio.Task.all_tasks():
    task.cancel()
  loop.run_forever() # restart loop
finally:
  loop.close()

在每個(gè) Task 中捕獲異常是必要的,如果不確定,可以使用

asyncio.gather(..., return_exceptions=True)

將異常轉(zhuǎn)換為正常的結(jié)果返回。

相關(guān)文章

最新評(píng)論