PyO3/tokioでPythonのイベントループをまわす

## はじめに

[PyO3/tokio](https://github.com/PyO3/tokio)というRustで実装されたPython3向けのasyncioイベントループをまわすライブラリがあります。

つい先日（2018.06.25頃）GitHubリポジトリがアーカイブされてしまいましたが、動かすためのメモを残しておきます。

## インストール

```shell-session
$ git clone https://github.com/PyO3/tokio.git
$ cd tokio
$ make build
```

ここでエラーが出てしまうので、以下のプルリクエストのパッチをあてて`cargo update`します。

https://github.com/PyO3/tokio/pull/135/files

```diff
diff --git a/Cargo.toml b/Cargo.toml
index 24cfe67..047a979 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,7 +29,7 @@ tokio-signal = "0.1"
 tokio-uds = "0.1"

 [dependencies.pyo3]
-version = "^0.2.6"
+version = "^0.2.7"
 features = ["python3"]

 [dev-dependencies]
diff --git a/src/lib.rs b/src/lib.rs
index 39510b4..4186461 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -49,7 +49,7 @@ pub use server::create_server;
 pub use client::create_connection;


-#[py::modinit("_tokio")]
+#[py::modinit(_tokio)]
 /// Asyncio event loop based on tokio-rs
 fn init_async_tokio(py: Python, m: &PyModule) -> PyResult<()> {
     let _ = env_logger::init();
```

## 動かす

asyncio使ってHTTPアクセスできる[aio-libs/aiohttp](https://github.com/aio-libs/aiohttp)モジュールと組み合わせて使ってみます。

```python
import aiohttp
import asyncio
import tokio

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    async with aiohttp.ClientSession() as session:
        html = await fetch(session, 'http://python.org')
        print(html[:100])

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
```

```shell-session
$ python tokiohttp.py
<!doctype html>
<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->
<!-
```

tokioのイベントループで動いてるかどうかわかりにくいので、ログ出力してみます。

```shell-session
$ RUST_LOG=debug python tokiohttp.py
DEBUG:tokio_core::reactor: adding a new I/O source
DEBUG:tokio_core::reactor: loop poll - 29.99µs
DEBUG:tokio_core::reactor: loop time - Instant { t: 1247017756623912 }
DEBUG:tokio_core::reactor: consuming notification queue
DEBUG:tokio_core::reactor: added a timeout: 0
DEBUG:tokio_core::reactor: scheduling direction for: 0
DEBUG:tokio_core::reactor: blocking
        :
DEBUG:tokio_core::reactor: loop process - 1 events, 307.091µs
DEBUG:tokio_core::reactor: loop poll - 12.654µs
DEBUG:tokio_core::reactor: loop time - Instant { t: 1247018957546308 }
<!doctype html>
<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->
<!-
DEBUG:tokio_core::reactor: updating a timeout: 0
DEBUG:tokio_core::reactor::timeout_token: cancel timeout 0
DEBUG:tokio_core::reactor: cancel a timeout: 0
DEBUG:tokio_core::reactor: loop process - 2 events, 569.892µs
DEBUG:tokio_core::reactor: loop poll - 11.526µs
DEBUG:tokio_core::reactor: loop time - Instant { t: 1247018958135120 }
DEBUG:tokio_core::reactor: updating a timeout: 1
DEBUG:tokio_core::reactor::timeout_token: cancel timeout 1
DEBUG:tokio_core::reactor: cancel a timeout: 1
DEBUG:tokio_core::reactor: scheduling direction for: 1
DEBUG:tokio_core::reactor: blocking
DEBUG:tokio_core::reactor: consuming notification queue
DEBUG:tokio_core::reactor: dropping I/O source: 1
DEBUG:tokio_core::reactor: scheduling direction for: 2
DEBUG:tokio_core::reactor: blocking
DEBUG:tokio_core::reactor: consuming notification queue
DEBUG:tokio_core::reactor: scheduling direction for: 3
DEBUG:tokio_core::reactor: blocking
DEBUG:tokio_core::reactor: loop process - 5 events, 332.505µs
```

というような感じでした。