從 yield from 到 await

貓橘毛 aka Lanfon
3 min readJun 1, 2017

--

這篇的主題是 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._looploop.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 coroutinecollections.abc 裡面是有定義的 —
abc.Coroutine ,繼承自 abc.Awaitable (實作 __await__) 並另外再實作 PEP342send(), throw()close()
abc.Coroutine 的做法其實就是把 generator 用在 coroutine 上的部份都獨立出來,讓 generator 跟 coroutine 的工作明確地分開。

下一篇會把 glossary 的其他部份講完,然後就終於要開始寫 asyncio 惹(?)
Bye~

--

--

貓橘毛 aka Lanfon
貓橘毛 aka Lanfon

Written by 貓橘毛 aka Lanfon

知,不知,上;不知,知,病。

No responses yet