memo

2016-11-26

Twisted が async def な coroutine に対応したらしいので、試してみる

あとついでに asyncio な reactor も試したりとか。

'''
twisted が async def な coroutine に対応したらしいのでそれ使ってみるのと、
ついでに asyncio な reactor 使って、その中で twisted と asyncio 両方の関数を
呼んでみるテスト。
'''
import asyncio
from twisted.internet import asyncioreactor
# twisted の reactor として、 asyncio ベースの物を使うよう設定する。
# (eventloop として、デフォルトではグローバルなもの使うとか書いてあるど、
# 実際は内部で新しく作成した eventloop を使ってるっぽい?)
asyncioreactor.install(asyncio.get_event_loop())

from twisted.internet import defer
from twisted.web import client as twClient
from aiohttp import client as aioClient


async def main(reactor=None):
    # twisted を通してページを取得する
    page1 = await twClient.getPage(b'http://localhost/')

    # asyncio (aiohttp) を通してページを取得する
    res = await _fut2deferred(aioClient.get('http://localhost/'))
    page2 = await _fut2deferred(res.read())

    # 両者はもちろん同じもの
    assert page1 == page2

    print('done')


# ensureDeferred は Deferred が出てくる coroutine を期待しているので、
# Future をテキトウに Deferred に変換するヤツ用意する。
# (将来的には twisted がこういう機能提供するつもりらしい?)
def _fut2deferred(fut):
    fut = asyncio.ensure_future(fut)
    d = defer.Deferred()
    fut.add_done_callback(lambda _: d.callback(fut.result()))
    # TODO: errback

    return d


if __name__ == '__main__':
    from twisted.internet import task

    # coroutine は ensureDeferred を使って Deferred に変換する。
    # asyncio とは違って、 reactor やらが勝手にやってくれるということは無さそう?
    task.react(lambda reactor: defer.ensureDeferred(main(reactor)))