kdnakt blog

hello there.

Rust dojo第72回を開催した

第72回です。前回はこちら。

kdnakt.hatenablog.com

[第72回の様子]

2023/03/29に第72回を開催した。

内容としてはRust By Example 日本語版20. 標準ライブラリのその他の「20.2. チャネル
」に取り組んだ。
参加者は自分を入れて6人。参加してまだ日の浅いメンバがドライバやってくれて、復習しながら進められたのでありがたかった!

[学んだこと]

  • 20.2. チャネル
  • スレッド間のコミュニケーションのために非同期のchannelを利用できる
  • SenderとReceiverの間に一方通行のやりとりができる
  • チャネルを生成するのは以下のようなコード
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;
// SenderやReceiverにつくジェネリクスは送受信されるデータの型
let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();
  • mpscって何だろう、と思ったけど、参加者が「multi producer single consumer」と教えてくれた。公式のドキュメントにもそう書いてあった。
    • FIFOなキューかどうかが気になってたけど、それも公式ドキュメントに書いてあった

doc.rust-lang.org

  • 作成したSenderでデータを送信するには以下のようにする
use std::thread;
static NTHREADS: i32 = 3;

let mut children = Vec::new();

for id in 0..NTHREADS {
    // 送信者エンドポイントをコピー
    let thread_tx = tx.clone();
    // スレッドを起動しメッセージを送信
    let child = thread::spawn(move || {
        // Resultが返ってくるのでエラーだったらpanicするためにunwrap()しておく
        thread_tx.send(id).unwrap();
        println!("thread {} finished", id);
    });
    // スレッドの終了を待機させるためにJoinHandleをベクタに詰めておく
    children.push(child);
}

// スレッドの終了を待機
for child in children {
    child.join().expect("oops! the child thread panicked");
}
  • Receiver側は以下のようになる
let mut ids = Vec::with_capacity(NTHREADS as usize);

for _ in 0..NTHREADS {
    // 取り出せるメッセージが存在しない場合、
    // recv()メソッドは現在のスレッドをブロックする。
    ids.push(rx.recv());
}

// 結果を出力
println!("{:?}", ids);

// 以下のようにスレッドの実行順に出力される
[Ok(1), Ok(0), Ok(2)]
  • 公式ドキュメントを見ている内に、Receiverがドロップされていたらメッセージ送信がエラーになると書かれているのを見つけた

doc.rust-lang.org

  • ので、実験してみた
use std::sync::mpsc::{Sender, Receiver};
use std::sync::mpsc;

let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();

// レシーバをドロップ
drop(rx);

tx.send(4).unwrap();

// 以下のようにpanicする
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SendError { .. }', src/main.rs:62:16
  • SendErrorというエラーが返ってくるらしい

[まとめ]

モブプログラミングスタイルでRust dojoを開催した。
Goにも似たようなチャネルの機能があって、そちらを知っていたので今日の内容は理解しやすかった気がする。

今週のプルリクエストはこちら。

github.com