Rust 100 Ex 🏃【35/37】 非同期ランタイム・Futureトレイト ～非同期のお作法～

前の記事

- [【0】 準備](https://qiita.com/namn1125/items/bd1b4cd028874189a3c1) ← 初回
- ...
- [【34】 `async fn`・非同期タスク生成 ～Rustの非同期入門～](https://qiita.com/namn1125/items/9c32b730a283ad76c891) ← 前回
- 【35】 非同期ランタイム・Futureトレイト ～非同期のお作法～ ← 今回

<details><summary>全記事一覧</summary>

- [【0】 準備](https://qiita.com/namn1125/items/bd1b4cd028874189a3c1)
- [【1】 構文・整数・変数](https://qiita.com/namn1125/items/c776768baec89b8a0438)
- [【2】 if・パニック・演習](https://qiita.com/namn1125/items/13870965e8273bc87bce)
- [【3】 可変・ループ・オーバーフロー](https://qiita.com/namn1125/items/4f57f8aede2f5201016f)
- [【4】 キャスト・構造体 (たまにUFCS)](https://qiita.com/namn1125/items/227ed5bbedbb775c5d27)
- [【5】 バリデーション・モジュールの公開範囲 ～ → カプセル化！～](https://qiita.com/namn1125/items/46721cceccbfa9ec3c7a)
- [【6】 カプセル化の続きと所有権とセッター ～そして不変参照と可変参照！～](https://qiita.com/namn1125/items/442de7798d49f777384c)
- [【7】 スタック・ヒープと参照のサイズ ～メモリの話～](https://qiita.com/namn1125/items/780d80e4340f0e34dbf6)
- [【8】 デストラクタ(変数の終わり)・トレイト ～終わりと始まり～](https://qiita.com/namn1125/items/7247edde3b6bd0b85b25)
- [【9】 Orphan rule (孤児ルール)・演算子オーバーロード・derive ～Empowerment 💪 ～](https://qiita.com/namn1125/items/e565713b423301a80c76)
- [【10】 トレイト境界・文字列・Derefトレイト ～トレイトのアレコレ～](https://qiita.com/namn1125/items/9060faee2965f23e0e3d)
- [【11】 Sized トレイト・From トレイト・関連型 ～おもしろトレイトと関連型～](https://qiita.com/namn1125/items/b68990712d379a3d6a49)
- [【12】 Clone・Copy・Dropトレイト ～覚えるべき主要トレイトたち～](https://qiita.com/namn1125/items/c6f34945f331c7229746)
- [【13】 トレイトまとめ・列挙型・match式 ～最強のトレイトの次は、最強の列挙型～](https://qiita.com/namn1125/items/6b2cc31d6a47f9ffaff6)
- [【14】 フィールド付き列挙型とOption型 ～チョクワガタ～](https://qiita.com/namn1125/items/6fe69d1cab6c7936c698)
- [【15】 Result型 ～Rust流エラーハンドリング術～](https://qiita.com/namn1125/items/698aafaf22ec4bfd1bde)
- [【16】 Errorトレイトと外部クレート ～依存はCargo.tomlに全部お任せ！～](https://qiita.com/namn1125/items/9dae7b728fa0668e4102)
- [【17】 thiserror・TryFrom ～トレイトもResultも自由自在！～](https://qiita.com/namn1125/items/d67006a29b7ff5d6148c)
- [【18】 Errorのネスト・慣例的な書き方 ～Rustらしさの目醒め～](https://qiita.com/namn1125/items/705829027661a38e4a4f)
- [【19】 配列・動的配列 ～スタックが使われる配列と、ヒープに保存できる動的配列～](https://qiita.com/namn1125/items/9c49fd4c08f3e61896c7)
- [【20】 動的配列のリサイズ・イテレータ ～またまたトレイト登場！～](https://qiita.com/namn1125/items/6e4dede789c6de97f396)
- [【21】 イテレータ・ライフタイム ～ライフタイム注釈ようやく登場！～](https://qiita.com/namn1125/items/9a1224abf733f29a980a)
- [【22】 コンビネータ・RPIT ～ :dragon: 「 `Iterator` トレイトを実装してるやつ」～](https://qiita.com/namn1125/items/27fe20f2d60803c94357)
- [【23】 `impl Trait` ・スライス ～配列の欠片～](https://qiita.com/namn1125/items/7601d0268293ce7fcf28)
- [【24】 可変スライス・下書き構造体 ～構造体で状態表現～](https://qiita.com/namn1125/items/a9acc7dc2ca7c4c55cc3)
- [【25】 インデックス・可変インデックス ～インデックスもトレイト！～](https://qiita.com/namn1125/items/bd43375362af10ea8b42)
- [【26】 HashMap・順序・BTreeMap ～Rustの辞書型～](https://qiita.com/namn1125/items/a2806cded12fa719a1cb)
- [【27】 スレッド・'staticライフタイム ～並列処理に見るRustの恩恵～](https://qiita.com/namn1125/items/5a4a09172834063268b1)
- [【28】 リーク・スコープ付きスレッド ～ライフタイムに技あり！～](https://qiita.com/namn1125/items/34a0aacd4d40f9234aef)
- [【29】 チャネル・参照の内部可変性 ～Rustの虎の子、mpscと `Rc<RefCell<T>>`～](https://qiita.com/namn1125/items/861e72dbb4b837508948)
- [【30】 双方向通信・リファクタリング ～返信用封筒を入れよう！～](https://qiita.com/namn1125/items/46f03de967d0de46737e)
- [【31】 上限付きチャネル・PATCH機能 ～パンクしないように制御！～](https://qiita.com/namn1125/items/d7ae8a205ee969339401)
- [【32】 `Send`・排他的ロック(`Mutex`)・非対称排他的ロック(`RwLock`) ～真打 `Arc<Mutex<T>>` 登場～](https://qiita.com/namn1125/items/eee890dc8672e975e70c)
- [【33】 チャネルなしで実装・Syncの話 ～考察回です～](https://qiita.com/namn1125/items/cc8bee3871b727e564e3)
- [【34】 `async fn`・非同期タスク生成 ～Rustの非同期入門～](https://qiita.com/namn1125/items/9c32b730a283ad76c891)
- [【35】 非同期ランタイム・Futureトレイト ～非同期のお作法～](https://qiita.com/namn1125/items/c840d48f8f558613ec10)
- [【36】 ブロッキング・非同期用の実装・キャンセル ～ラストスパート！～](https://qiita.com/namn1125/items/39c139da3f1f26264353)
- [【37】 Axumでクラサバ！ ～最終回～](https://qiita.com/namn1125/items/bae492f823fbe60e9974)
- [【おまけ1】 Rustで勘違いしていたこと3選 🏄🌴 【100 Exercises To Learn Rust 🦀 完走記事 🏃】](https://qiita.com/namn1125/items/2a59f486cce30fd2b889)
- [【おまけ2】 【🙇 懺悔 🙇】Qiitanグッズ欲しさに1日に33記事投稿した話またはQiita CLIとcargo scriptを布教する的な何か](https://qiita.com/namn1125/items/8e552694b389c5b13b5e)
</details>

[100 Exercise To Learn Rust](https://rust-exercises.com/) 演習第35回になります！

:::note warn
8章の非同期について、全体的に筆者の理解度が低いです...他の本とかも読んでる最中...マサカリ大歓迎です！

記事は執筆時点での理解という感じです
:::

今回の関連ページ

- [8.3. Runtime](https://rust-exercises.com/08_futures/03_runtime)
- [8.4. Future trait](https://rust-exercises.com/08_futures/04_future)

# [[08_futures/03_runtime](https://github.com/mainmatter/100-exercises-to-learn-rust/blob/main/exercises/08_futures/03_runtime/src/lib.rs)] 非同期ランタイム tokio (もとい演習自体は `Arc` の使用)

- [8.3. Runtime](https://rust-exercises.com/08_futures/03_runtime)

問題はこちらです。

```rust:lib.rs
// TODO: Implement the `fixed_reply` function. It should accept two `TcpListener` instances,
//  accept connections on both of them concurrently, and always reply clients by sending
//  the `Display` representation of the `reply` argument as a response.
use std::fmt::Display;
use tokio::io::AsyncWriteExt;
use tokio::net::TcpListener;

pub async fn fixed_reply<T>(first: TcpListener, second: TcpListener, reply: T)
where
    // `T` cannot be cloned. How do you share it between the two server tasks?
    T: Display + Send + Sync + 'static,
{
    todo!()
}
```

<details><summary>テストを含めた全体</summary>

```rust:lib.rs
// TODO: Implement the `fixed_reply` function. It should accept two `TcpListener` instances,
//  accept connections on both of them concurrently, and always reply clients by sending
//  the `Display` representation of the `reply` argument as a response.
use std::fmt::Display;
use tokio::io::AsyncWriteExt;
use tokio::net::TcpListener;

pub async fn fixed_reply<T>(first: TcpListener, second: TcpListener, reply: T)
where
    // `T` cannot be cloned. How do you share it between the two server tasks?
    T: Display + Send + Sync + 'static,
{
    todo!()
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::net::SocketAddr;
    use std::panic;
    use tokio::io::AsyncReadExt;
    use tokio::task::JoinSet;

    async fn bind_random() -> (TcpListener, SocketAddr) {
        let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
        let addr = listener.local_addr().unwrap();
        (listener, addr)
    }

    #[tokio::test]
    async fn test_echo() {
        let (first_listener, first_addr) = bind_random().await;
        let (second_listener, second_addr) = bind_random().await;
        let reply = "Yo";
        tokio::spawn(fixed_reply(first_listener, second_listener, reply));

        let mut join_set = JoinSet::new();

        for _ in 0..3 {
            for addr in [first_addr, second_addr] {
                join_set.spawn(async move {
                    let mut socket = tokio::net::TcpStream::connect(addr).await.unwrap();
                    let (mut reader, _) = socket.split();

                    // Read the response
                    let mut buf = Vec::new();
                    reader.read_to_end(&mut buf).await.unwrap();
                    assert_eq!(&buf, reply.as_bytes());
                });
            }
        }

        while let Some(outcome) = join_set.join_next().await {
            if let Err(e) = outcome {
                if let Ok(reason) = e.try_into_panic() {
                    panic::resume_unwind(reason);
                }
            }
        }
    }
}
```
</details>

[前回](https://qiita.com/namn1125/items/9c32b730a283ad76c891) 解説した通り、 **非同期処理は `Send` を要求** します！そして、 `reply: T` を複製せずに **複数タスク(複製スレッド)で所有したい** とくれば...？

:::note
独り言...**「「「[前回](https://qiita.com/namn1125/items/9c32b730a283ad76c891)作成した図、今回載せれば良かった...！！！！」」」** というわけで前回の[第34回](https://qiita.com/namn1125/items/9c32b730a283ad76c891)も合わせて読んでほしいです :bow:

第34回に合わせて図を作成してしまい、作り直す体力がないです... :sweat_smile:
:::

## 解説

そうですね、 **[`Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html) の出番です**！というわけで、非同期処理でもお世話になりましょう。

( [次回](https://qiita.com/namn1125/items/39c139da3f1f26264353) にて非同期専用の [`Mutex`](https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html) がある話等をするつもりですが、)このように、非同期処理も並行処理の一種で、 `Send` の制約がある仲間ですから、まるまる[7章](https://qiita.com/namn1125/items/5a4a09172834063268b1)で学んだ知識が活かせます！

```rust:lib.rs
use std::sync::Arc;

pub async fn fixed_reply<T>(first: TcpListener, second: TcpListener, reply: T)
where
    // `T` cannot be cloned. How do you share it between the two server tasks?
    T: Display + Send + Sync + 'static,
{
    let reply = Arc::new(reply);
    let reply2 = Arc::clone(&reply);
    tokio::spawn(listen(first, reply));
    tokio::spawn(listen(second, reply2));
}

async fn listen<T>(listener: TcpListener, reply: Arc<T>)
where
    T: Display + Send + Sync + 'static,
{
    loop {
        let (mut socket, _) = listener.accept().await.unwrap();
        let reply = Arc::clone(&reply);

        tokio::spawn(async move {
            let reply = reply.to_string();
            socket.write_all(reply.as_bytes()).await.unwrap();
            socket.flush().await.unwrap();
        });
    }
}
```

[前回](https://qiita.com/namn1125/items/9c32b730a283ad76c891)自分は「tokioは複数スレッドを管理する」と言ったのですが、今回の [Book](https://rust-exercises.com/100-exercises/08_futures/03_runtime) には「マルチスレッドとシングルスレッドの2つのフレーバーがあり選べて、 `#[tokio::main]` マクロを使った場合はマルチスレッド、 `#[tokio::test]` マクロを使用した場合はシングルスレッドになる」と解説されていたりします。

デッドロックってマルチスレッド版だと気づきにくかったりしますし、テストがシングルスレッドなのは中々ありがたいですね。

その他、「 `tokio::spawn` は(スコープ `async {}` を跨ぐ値について[^static]) `'static` を要求する」とありますが、こちらは `std::thread::spawn` と同様ですね。タスクがいつまで生きているかはわかりません！

[^static]: ローカルで生成される値への参照等であれば `'static` でなくとも `.await` は跨げるようです。 Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9ca535b6f390d2ae81cdc7b3c3cd39a6

# [[08_futures/04_future](https://github.com/mainmatter/100-exercises-to-learn-rust/blob/main/exercises/08_futures/04_future/src/lib.rs)] FutureトレイトとSendトレイト

- [8.4. Future trait](https://rust-exercises.com/08_futures/04_future)

問題はこちらです。久々のコンパイルを通してください問題になります。

```rust:lib.rs
//! TODO: get the code to compile by **re-ordering** the statements
//!  in the `example` function. You're not allowed to change the
//!  `spawner` function nor what each line does in `example`.
//!   You can wrap existing statements in blocks `{}` if needed.
use std::rc::Rc;
use tokio::task::yield_now;

fn spawner() {
    tokio::spawn(example());
}

async fn example() {
    let non_send = Rc::new(1);
    yield_now().await;
    println!("{}", non_send);
}
```

しまった...こっちも[前回](https://qiita.com/namn1125/items/9c32b730a283ad76c891)解説してしまいました... :sweat_smile: **`Send` ではない値は `.await` を跨げません** 。

## 解説

`Send` を実装していない型であったところで、 `.await` より前にドロップしてしまえば問題ないので、そのように書いちゃりましょう！

```rust:lib.rs
async fn example() {
    {
        let non_send = Rc::new(1);
        println!("{}", non_send);
    }
    yield_now().await;
}
```

`{}` 内に収めることで `Rc` を `.await` 前にドロップさせています。 `drop` 関数等を使っても良いかもしれません。

その他 [Book](https://rust-exercises.com/100-exercises/08_futures/04_future) で取り上げられている大きめなトピックとして、 `async fn` の正体、 `Future` トレイトの話があります。Rustでは非同期もトレイトで説明されるのです！

```rust:Rust (脱糖前)
async fn xxx(...) -> T {
    // ...
}
```

↓

```rust:Rust (脱糖後)
fn xxx(...) -> impl Future<Output = T> {
    // ...
}
```

※ 手書きの場合は `+ Send + 'static` みたいな形でさらに追加で色々付くことも...？また脱糖についての正確性は調べられてないです( `cargo expand` でわかるのかな...？)

「 `Future` トレイトを実装した型は **ステートマシンである** 」という内容を始めとし、かなり興味深い説明が書かれているので是非読んでほしいです！(筆者に説明の力量がない定期)

[前回](https://qiita.com/namn1125/items/9c32b730a283ad76c891)「 `.await` を跨ぐには `Send` が要る（ｷﾘｯ」と筆者はぼかしながらテキトーに話していましたが、ちゃんとこれに対する理由も `Future` トレイトを実装した列挙体を例に挙げ説明されていたりします。

:::note 
<b><ruby>Future<rt>未来</rt></ruby>って200通りあんねん...</b>

上記の `impl Future` 脱糖について、たまに型を手書きする必要があったりして、その時に筆者がよくお世話になっているQiita記事様のリンクを掲載させていただきます :bow:

[非同期Rustパターン](https://qiita.com/legokichi/items/4f2c09330f90626600a6)

https://qiita.com/legokichi/items/4f2c09330f90626600a6

いや、パターン多すぎるだろ...非同期への理解もかなり深まりそうです
:::

では次の問題に行きましょう！

次の記事: [【36】 ブロッキング・非同期用の実装・キャンセル ～ラストスパート！～](https://qiita.com/namn1125/items/39c139da3f1f26264353)

<details><summary>登場したPlayground</summary>

(実際に無効化したことはないですが、)Rust Playground上のデータが喪失する可能性を鑑みて、一応記事にもソースコードを掲載することとしました。

URL: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9ca535b6f390d2ae81cdc7b3c3cd39a6

```rust:Rust
use tokio;
use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() {
    tokio::spawn(async move {
        let s = 10_u32;
        let r = &s;
        sleep(Duration::from_millis(100)).await;
        println!("{}", r);
    }).await.ok();
}
```
</details>