第72回です。前回はこちら。
[第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なキューかどうかが気になってたけど、それも公式ドキュメントに書いてあった
- 作成した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がドロップされていたらメッセージ送信がエラーになると書かれているのを見つけた
- ので、実験してみた
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にも似たようなチャネルの機能があって、そちらを知っていたので今日の内容は理解しやすかった気がする。
今週のプルリクエストはこちら。