LoginSignup
17
8

More than 3 years have passed since last update.

Rustの非同期フレームワークtokioを少しずつ試しながら勉強する その1

Last updated at Posted at 2018-12-24

この記事は、Rust Advent Calendar その2 の25日目の記事です。

tokioいいらしいよ!という話を、最近良く聞くので、試してみようとしたんだけど、どうやって使ったら良いのかわからない・・・
サイトのサンプルとか見てみたけど、Futureとかよくわからない・・・
そんなお悩みのあなたに!!

私も最初そうでした。
で、少しずつ動かしながらやってみたら、だんだんわかってきたので、その軌跡をここに残しておきます。

対象読者
- Rustの基本的な構文がわかっている人。実際にコーディングしたことがある人。
- tokio による非同期処理の実装方法を知りたい人。

注意事項(2019.8.19追記)
本記事で使っている Future は、futures-rs( https://github.com/rust-lang-nursery/futures-rs )の0.1です。
今は Future もstdに取り込まれ、async/await も実装間近ですので、この記事の内容は参考程度に考えてもらうと良いかもしれません。

tokio

tokioのサイトはこれ。
ソース眺めたりするのに、手元に git clone しておくと良い。
https://github.com/tokio-rs/tokio

準備

プロジェクトを作ったら
Cargo.tomlを編集して、依存ライブラリに tokio と futures を追加

[dependencies]
tokio = "0.1.13"
futures = "0.1.25"

なにはともあれ tokio::run してみる

https://github.com/tokio-rs/tokio
ここにあるサンプルを見てみると、main()の最後に

// Start the Tokio runtime
tokio::run(server);

とある。
server は何者かわからないが、とにかくこれで tokioランタイムを起動する、ということらしい。

さて、tokio::run()の引数は何を要求されるのだろう?リファレンスを見てみる。
https://docs.rs/tokio/0.1/tokio/runtime/fn.run.html

pub fn run<F>(future: F) 
where
    F: Future<Item = (), Error = ()> + Send + 'static, 

とある。
Future!!! つまり未来!!
未来って何?

またリファレンスを見てみる
https://docs.rs/futures/0.1.2/futures/trait.Future.html

pub trait Future {
    type Item;
    type Error;
    fn poll(&mut self) -> Poll<Self::Item, Self::Error>;

    fn wait(self) -> Result<Self::Item, Self::Error> where Self: Sized { ... }
    fn boxed(self) -> BoxFuture<Self::Item, Self::Error> where Self: Sized + Send + 'static { ... }
//この下にずっと、たくさんメソッドが書いてある

Futureはトレイト。メソッドがいっぱいあって、なんじゃこりゃあ!ってなるけど、よく見ると、Required Method(=こちらで実装しないといけないメソッド)は、

fn poll(&mut self) -> Poll<Self::Item, Self::Error>

だけ。
あと、関連型として、ItemとErrorを定義せよ、とある。

んーじゃあ、試しに Future を実装する struct を作ってみますか。

その際考えないといけないのは、
- Itemに何を指定するか
- Errorに何を指定するか
- poll() の中で何をするか
- poll() は何を返せばいいか

Item, Error... 何を意味するのかは置いといて、もう一度 tokio::run() の定義を見てみると、

pub fn run<F>(future: F) 
where
    F: Future<Item = (), Error = ()> + Send + 'static, 

Item = (), Error = () とある!じゃあどちらも () にしとけば良いってことね。

poll() の中で何をするか。とりあえず println! でなんか書いておこう。

poll() は何を返せばよいか。定義によると、

fn poll(&mut self) -> Poll<Self::Item, Self::Error>

poll は Pollを返せと。

・・・・解せぬ。
Pollの定義を見てみる。

type Poll<T, E> = Result<Async<T>, E>;

説明によると

Ok(Async::Ready(t)) ----- 成功!
Ok(Async::NotReady) ----- まだ結果が取れてない!
Err(e) ----- 失敗した!

このどれかを返せということらしい。
んじゃ、まずは成功を返しとけばいいか。

ということで、できたソース。

use tokio::prelude::*;  //tokioでよく使うものをまとめて使えるようにする

struct FutureTest {
}

impl Future for FutureTest {
    type Item = ();
    type Error = ();
    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        println!("poll called!");
        Ok(Async::Ready(()))
    }
}

fn main() {
    let f = FutureTest{};

    tokio::run(f);
}

出力
poll called!

poll呼んでくれた!

・・・で、これ何が嬉しいの?
その2につづく。

今回作ったソースはこちら
https://github.com/mas-yo/learn-tokio-step-by-step/tree/master/learn-tokio-1

その2
https://qiita.com/mas-yo/items/c5cbfe4dfbbe1cd9f947

17
8
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
8