從 yield from 到 await
這篇的主題是 coroutine between yield from
and await
.yield
用在 coroutine 的部份就不講了,有興趣的話可以參考 Game of Life 的實作 with function only, with coroutines;coroutine 用的 methods 定義在 PEP342。
yield from
前一篇有講過 `yield from` 的寫法,這裡就只專注在 with asyncio 的用法。
一個用 `yield from` 驅動的 coroutine 會長得像這樣:
如果沒有用 asyncio.coroutine
decorate 的話,它就只是個普通的 generator
,所以它其實可以用 generator
的眼光來看待,那我們就進去看 asyncio.sleep
到底是怎麼做的: (from py36 lib/asyncio)
前一篇講過 loop.create_future()
的用法了,這裡就不再重提。
future._loop
跟 loop.create_future()
綁到的是同一個 loop
;這裡用 call_later
產生 delay call , loop
會在 delay
的時間到的時候才呼叫 _set_result_unless_cancelled()
,所以從流程上來說它應該會在 return (yield from future)
的地方 block ,往下可以看到 Future
是怎麼做的: (from py36 lib/asyncio)
另一篇講過 yield from
實際上是認 Iterable
,也就是 __iter__
protocol ,從 Future 實作 __iter__
的方式可以了解 Future
在未完成之前都會 self-loop(yield self)。
await
從 PEP492 加入的 pre-keyword (在 3.7 才會正式升格成 keyword),await
只能在用 async
定義的 coroutine function (or method) 裡使用;它所使用的 protocol 是 __await__
。(這也是為什麼上面有 __await__ = __iter__
)
用 await
寫的 coroutine
和用 yield from
之間其實沒太大差異,簡單來說就是把 yield from
用的 __iter__
改成用 __await__
這樣。
coroutine
這裡要再回頭看 PEP492 的 glossary,裡面對於 coroutine 的定義是:
Either native coroutine or generator-based coroutine.
上一篇講過兩者之間的差別就是用 await
/ yield from
驅動的,這邊要再細講的是 native coroutine
在 collections.abc
裡面是有定義的 —
abc.Coroutine
,繼承自 abc.Awaitable
(實作 __await__
) 並另外再實作 PEP342 的 send()
, throw()
跟 close()
。abc.Coroutine
的做法其實就是把 generator 用在 coroutine 上的部份都獨立出來,讓 generator 跟 coroutine 的工作明確地分開。
下一篇會把 glossary 的其他部份講完,然後就終於要開始寫 asyncio 惹(?)
Bye~