「 Rust でゲーム・サーバーを作ろうと思っても、あれができない、これができない、と すぐ行き詰ってしまう……☆
古い知識のアップデートが必要だぜ☆」
Rust はどのようにして安全な並列処理を提供するのか
並行性
「 通信処理は、もっと整理された枠組みの 並列処理(Parallel processing) の一部になっているようだな☆」
「 シングル・コアのプログラミングからは 今日から卒業か☆?」
「 シングル・プロセッサ、 マルチ・コア、 マルチ・スレッド なの?」
「 そうそう……、おさらいしようぜ☆
特に 並列性(へいれつせい; ペアラレズン; parallelism) と 並行性(へいこうせい; クンコレンシー; concurrency) は なんど読んでも見間違うぜ☆」
「 このアイコンは 産業革命頃の家かも知らないが とりあえず インターネットが普及した現代としよう☆」
「 突如として 4つの家が 謎のコネクションを確立したとしよう☆」
「 本来ばらばら だった この家みたいなアイコン…… Node(ノード)とでも言うかだぜ☆、
ノードが集まって 1つのことをしようとするコンピューターたちを Cluster(クラスター)と呼ぶ☆
この スケール の話しだと マルチ・プロセッサ になる☆」
「 ノード1つで クラスター と言い張ることも可能☆ リクツとしては……☆」
「 突如として 3台のPCが 謎のコネクションを確立したとしよう☆」
「 これも 本来ばらばら だった ノードが集まって 1つのことをしようとするので クラスター だぜ☆
この スケール でも マルチ・プロセッサ になる☆」
「 ノード1つで クラスター と言い張ることも可能☆ リクツとしては……☆」
「 1つのPCに 32bit CPUが2基 積んであって 64bit CPU……いや こんなPC聞いたことないぜ☆
セガ・サターンでしか聞いたことない☆
サーバー・マシンなら 電話ボックスみたいな大きな1台の箱の中に たくさん CPU が詰め込んであるものはあるが
CPU だけ詰め込んであっても嬉しくなくて 電源もファン(換気扇)もハードディスクも付いている……、
あれは ブレード・サーバー という鉄のタンスみたいな中に 8つぐらいPCを挿してるわけで PCの中にCPUが複数あるといえるかは分からない……☆
だいたい 廃熱音で耳やられるとか 個人が お目にかかることもない☆
今どきのPCは……☆、」
「 PCには1つのCPUが積んであって、1つのCPUが 複数のCPUのふり をしてくれる マルチコア だぜ☆」
「 小さく造って 詰め込んでいるからだぜ☆
光の速さは 1秒間に 地球を およそ7周半と決まっているように、CPUの仕事の速さは限界に達している☆
だから CPUのコア数 を増やす方向に発展してるんだぜ☆」
「 これも 本来ばらばら だった ノードが集まって 1つのことをしようとするので クラスター だぜ☆
この スケール だと シングル・プロセッサ になる☆
CPUは Central Processing Unit の頭文字だからな☆」
「 クラスター使いの作業相手は ノード だからな☆ どんなスケールかは関心がないぜ☆」
「 お父んは クラスター のことを ぶどう か何かだと思ってるだろ☆」
「 ノードの数を減らすことを スケールイン(Scale in) 、ノードの数を増やすことを スケールアウト(Scale out) と言うそうだぜ☆」
「 ノードが使っているCPUの性能を下げることを スケールダウン(Scale down) 、性能を上げることを スケールアップ(Scale up) と言うそうだぜ☆」
「 ここまでの説明で ひとまず、 シングル・プロセッサ で マルチ・コア なのは PCの教養 みたいなもので 明らかに区別できるだろう☆
次☆」
「 コンピューターから見れば 人間はターミナルだし、
人間から見れば コンピューターはターミナルだぜ☆」
「 人間は ジョブ をこなすために コンピューターを使う☆」
「 シングル・ジョブとか、 マルチ・ジョブ といった言葉は聞いたことがないぜ☆
なぜなら マルチ・ジョブ が あたりまえ だからだぜ☆」
「 で、1時間に1つずつ ジョブをこなしていくのなら、 シングル・タスク だぜ☆」
「 いや、一度に3つこなせる、というのなら、 マルチ・タスク だぜ☆」
「 なんで 3時間 かかっていたことを 1時間 で できるんだぜ☆?」
「 作業を共通化して1回分にしたり、 片手が空いていたときに 他にできることを やってしまったり、
連絡したのに 返事が返ってこない待ち時間に 他の作業をしたりと
時間あたりのCPU利用率を上げていくわけだな☆ それと……☆」
「 作業を中断したり、再開する機能が OS(Operating system; オペレーティング・システム) に付いている☆
時間がかかっている作業は yield(イヨード; 譲る)して 別の作業に時間を渡すぜ☆」
「 プログラマーが考えなくても オペレーティング・システムが ワーク・シェアリング(作業の配分) を やってくれるわよね。楽よね~」
「 Aさんは作業を指示しただけで、実際働いてるのはCPUなんで☆
シングル・コア から見れば ↑こんな図だぜ☆」
「 司令塔のマスターと 駒のスレーブとの連携がヘタクソだったり、
せっかく並列計算しても コア間で データの受け渡しが遅くて オジャンになったり、
1つのコアだけ早く仕事が終わって遊んでたりすると 結局 トントン になるんだがな☆」
「 人間から見ると ジョブ、
コア から見ると プロセス(Process) に名前を変えるが……☆、」
「 人間は 大雑把に指示を出すが、 その指示は 言ってない多くのことを含むんだぜ☆
ピザ屋は ピザ配ってんのかというと 生地を伸ばすこともすれば 焼くこともしているだろ☆ 見えないプロセスがあるんだぜ☆
でも ジョブは ピザ屋 だぜ☆」
「 ジョブは 大雑把すぎるんだぜ☆ 人間に向けた ラベル のようなもの☆」
「 Enter キーを押すまでに 伝えた内容が ジョブ だぜ☆」
「 ジョブ(仕事)に エンター(入る) するキー(ボタン)だったのね」
「 コンピューターは 1つのジョブを 複数のプロセスを 順番に行うが、これは 連続して行う1つずつのプロセスだぜ☆
マルチ・プロセスとは呼ばない☆」
「 もし マルチ・プロセス という用語が出た場合は、同時並行しているプロセスのことだと思えだぜ☆」
「 話しを戻す☆
プロセスは、さらに スレッドという単位に分けて、時間を振り分けている☆
yield で時間を譲るのは実際には スレッド単位で行われる☆」
「 CPU は Central Processing Unit の頭文字なんで、
コアが扱っているのが Process(プロセス) なのは 分かるだろ☆
で、このとき……☆」
「 全部のスレッドが、同じ CPU を使っているなら
シングル・コア、 マルチ・スレッド プログラミング だぜ☆」
「 1つのプロセスの いずれかのスレッドを 別の コア に振り分けてこそ マルチ・コア プログラミング だよな☆」
「 マスターで1個使ってるの もったいないよな☆ マスターも働けよ☆」
「 プロセスの中で なんで スレッドに分かれて、 スレッドは 何やってるのかと言うと……☆」
「 人類が カタカタ とキーボードを打っている間の退屈な待ち時間、
せわしなく ディスプレイに向かって バスに乗って画像を転送している時間、
インターネットからファイルをダウンロードしている待ち時間、
いろんな相手との間で 待ち をするからだぜ☆ 待ち の間に何もできないのが もったいないので スレッドで分けている☆」
「 スレッドとは 言ってしまえば ある種のチームを組んだもので、 待ち時間になったら譲る ことを決めたメンバーだぜ☆」
「 マルチ・コア・プログラミングも OS が勝手に やってくれないのかだぜ☆?」
「 マルチ・コア にした方が 作業が速く終わるのか、 シングル・コア にした方が 作業が速く終わるのか
オペレーティング・システムは 知ってないので、やってくれないぜ☆」
「 マルチ・スレッド・プログラミングと マルチ・コア・プログラミング には そんなに差があるの?」
「 マルチ・スレッド・プログラミングは人類には早すぎた と言うプログラマーがいたり、
PCはマルチ・コアになってから何十年も経つのに、ほとんどのソフトウェアはマルチ・コア・プログラミングで書かれていない
という意見も目にするぜ☆」
「 マルチ・コア・プログラミング というのは言ってしまえば マルチ・スレッド・プログラミング の特殊な例の1つに過ぎないわけだが、
コアとは結局 CPUのふりをしているものだから CPU と 同じと考えれば、
突き詰めれば シングル・プロセッサーと マルチ・プロセッサー の違いだぜ☆ 何が違うか 考察してみようぜ☆?」
「 シングル・プロセッサー には 何か大きな利点があるはずだぜ☆ マルチ・プロセッサーにない大きな利点が☆」
「 東京23区内暮らしか、一番近いコンビニが10km先とか それぐらいの違いはあるだろうな☆」
「 じゃあ ちょいと 隣のノードに データを渡してくれだぜ☆ ちょっと使うんで☆」
「 CPUのコアは CPUの中にあるから すぐ隣だけど、
インターネットにつながっている お隣の家って どこにあるの?」
「 光を頑なに拒み、ADSL回線を使い続けているノードだったら どうすんだぜ☆?」
「 そんなノードは 早く通信切断した方がいいかもしれないな☆」
「 Windowsアップデートで ノードのPCが再起動されたら どうすんの?」
「 通信が失敗することを考えながら プログラムを組まなくちゃいけなくない?」
「 マルチ・コア・プログラミングは、 通信プログラム なのかだぜ☆?」
「 クラスターやるなら ノードが メキシコ にあるのか CPUの中にあるのか 関心がないし、
並列処理 するのなら うまみ は 複数台のPC を使うことだろ☆
マルチ・コア・プログラミング やるのは 通信プログラミング やることに違いないぜ☆」
C++ マルチスレッド 入門
マルチスレッドプログラムのバグ
マルチコア向けソフトウェア開発/デバッグの基礎と実際
「 マルチ・スレッド・プログラミングが なぜ 人類には早すぎた と言われるのか、
これは 他のプログラム言語でも言えることだから、↑先人が書き残したものを当たろうぜ☆」
「 何が そんなに嫌われているの?
プログラミングのテクニックで 楽にできないの? プログラマーは無敵じゃないの?」
「 一番よく耳にするのは、
シングル・スレッドのプログラムでは起こらなかったことが、マルチ・スレッドのプログラムでは起こる
からだぜ☆」
「 たった2つ のことなんだぜ☆ その2つのことを扱うには、人類には早すぎた☆ 例を示そう☆」
館内放送「 ホワイト・ボードに書かれている数を 1大きい数に 書き直してください」
「 どっちが早く立ち上がろうとも 結局 12 なんじゃないの?
というか 片方が立ち上がったんなら もう片方は 立ち上がらなくてよくない? 何しにホワイトボードに向かうの?」
「 マルチ・コア・プログラミング(並列性)の話しでもあることに 気をつけてくれだぜ☆」
「 よし、12に 書き換えたぜ☆ 黄緑さんは 仕事をした☆」
「 ホワイトボードに書かれている数 って言ってたけど、
最初にみた数と、書き直された数の どっちを指しているの?」
「 ジョブを受けてから、最初にホワイトボードを 見たときの数だぜ☆」
「 腹いせか知らないけど 上から 12 で書き殴ったわよ!」
「 今、メキシコから間に合った 桃色さん の場合はどうだろう☆?」
「 ジョブを受けて 初めてホワイトボードを 見た時の数より 1大きくしたぜ☆」
「 なぜ 東京23区内の桃色さんと メキシコの桃色さんで 結果が変わってしまったのだろうか……☆?
プログラマーは どちらの結果を望んで 館内放送を出したんだぜ☆?」
「 ノードの都合で 結果が変わるんなら、プログラミングなんて 成り立たなくない?!」
「 しかし 都合がつかずに動けない方は後回しにして 動けるやつに どんどん仕事してもらいたい のが
そもそもの マルチ・スレッド(並行性) の意義だぜ☆
ノードの都合で 行動は変わって欲しいし、結果は変わってほしくないんだぜ☆」
「 タイミング などという陳腐な理由で プログラミングの手順を入れ替えられてしまったら、プログラミングの概念が崩れる……☆」
「 シングル・スレッド・プログラマーは まず びっくりするだろ☆
プログラムの経験があるから大丈夫……、という その経験から 真っ先にウソを付くぜ☆」
館内放送「2つのボールを自分のポケットに入れてください。2つとも入れたら、2つとも台に戻してください」
「 だから何で 2人が立つの!
片方が立ち上がったんなら もう片方は 立ち上がらなくてよくない? 何しにボールに向かうの?!」
「 マルチ・コア・プログラミング(並列性)の話しでもあることに 気をつけてくれだぜ☆」
「 学習しなさいよ! 歴史のelse は繰り返したくないのよ!」
「 よし、2人とも 1つ目のボールを 自分のポケットに入れたな☆」
「 ささ、2つ目のボールをよこせだぜ☆ 3分間だけ待ってやろう☆」
「 桃色さんが 遅れてやってきてくれれば 何も問題はなかった……☆」
「 遅れてくるとか 遅れてこないとか、 タイミングでデッドロック してんじゃないわよ!」
「 データレースも、デッドロックもそれぞれ 根本的な解決から 対処的な解決まで
さまざまな事態に向けて リーズナブルに合わせた個々の解決方法が すでに知られている☆」
「 その個々の解決方法が、 シングル・スレッド・プログラミングを使った方がマシかも であったなら、
小さな問題は解決したけど 大きな問題は解決していない、
マルチ・スレッド・プログラミング(並行性)の解決方法にはならない ことは ご理解いただけるかだぜ☆?」
「 タイミングで崩れたりしない シングル・スレッド・プログラミング って、すごくない?
プログラミングのすごさの9割9分の理由は 割り込み を気にしなくていいことなんじゃないの?」
「 割り込み を気にしなくていいなら、むしろ マルチ・スレッド・プログラミング や
マルチ・コア・プログラミングを 最大限に活かせる場面だぜ☆ 言ってしまえば……☆」
「 従業員が2人いて 同時並行で働いていれば マルチ・スレッド だぜ☆
片方は 車を設計していて、 片方は 税金を計算している☆
ただし、自分にやることがなくなっても 隣の仕事を横取りできない☆ 専門職だから、割り込めないぜ☆
これは ある意味 並行処理の完成形その1 ☆」
「 そもそも 何の縁もなく 割り込みもない人たちが 世界中のどこかで働いていれば 並行処理なわけだぜ☆
しかし わたしたちは、 割り込みする並行処理 をしたいわけだぜ☆」
「 ひとり山奥にこもって ろくろを回しながら 土器 作ってるわけにも いかないですもんね」
「 コミュニケーション能力 があれば みんなで割り込んでも 大丈夫だろう☆?」
「 例えば 水色のボールを先にポケットに入れ、オレンジ色のボールを次にポケットに入れる というルールを
徹底すれば このケースでは デッドロックしない……☆
でも 自信満々のおっさんや 若いのが現れて
『だいじょーぶ、だいじょーぶ』と言いながら 軽くひょいっと 俺流 で オレンジ色のボールを
先にポケットに入れて デッドロック するぜ☆」
「 なんで 俺流 で やってしまうの?! つまみだせないの!?」
「 ルールが整備されていないところで 発揮されるのが コミュニケーション能力 だろ☆
ルールが整備されているとは知らずに コミュニケーション能力 を発揮したんだろ☆
どちらかというと コミュニケーション能力 が無く ルール通りに動くロボットの方が失敗しない☆」
「 まあ ルール通り動いて 水色のボールをポケットに入れた瞬間 ぽっくり逝ってしまう爺さんも いるかも知れない☆ デッドロックする☆」
「 ぽっくり逝って 強制終了するのは シングル・スレッド・プログラミングでも同じだぜ☆」
「 どんどん 割り込み いらっしゃい、というプログラムを組むことも ある意味、
並行処理の完成形その2 ☆
これは 何も書き込んだりしない 読み取り専用プログラムなら できる……☆」
「 昔のコンピューターは、完全解明されていることを 計算するものだった☆
計算結果は 正解だぜ☆」
「 2019年現在のコンピューターは、それっぽい答えを当てにいくものだぜ☆
計算結果は 多分 いい感じのものかもしれないぜ☆」
「 限られた範囲の中で正しい答えを返すコンピューターは、
限られた範囲の外へ出て 応用できる範囲を広げたという意味で、大きな進歩だぜ☆
人類の 制度 の方が コンピューターの進めた一歩に 付いてこれてないだけで☆」
「 そして コンピューターによって 計算結果が異なる ということが 起こり始めた☆
コンピューターへの関心は 答え から、 精度 へ 移ったんだぜ☆」
「 この変化が、 マルチ・コア・プログラミング(並列性) にとって 良い変化だったわけだぜ☆」
「 昔のコンピューターは 計算にかかる時間 が能力の目安だったんだぜ☆
速く計算が終われば 性能が高い☆」
「 では、計算にかかる時間を縮めることが評価されるとして、
マルチ・コア・プログラミング にすることで、
コアの数を 増やせば増やすほど、 計算にかかる時間を縮められるか☆?」
「 これには アダムール が コアの数を増やしても計算にかかる時間は縮まらなくなると 悲観的な法則を示している☆
60分かかる仕事のうち 並列処理できるのが57分で、残りの3分は 分配できないとしよう☆」
「 じゃあ この仕事は コアを何個積んでも 3分より短くならない☆
3分は20分の1だから、この時点で、20倍を超える高速化は できないことが確定する☆」
「 57÷3=19 だから、全部で20コアあれば 最速の3分ね。
21コアにしても 誰にでも振り分けられる仕事が 57÷20 = 2.85分 で終わるだけで、
並行できない仕事の 3分 は 必ず かかってしまうわよ」
「 全体の5% が並列化できない仕事は、21コア以上に増やしても 無意味かだぜ☆?」
「 計算にかかる時間 が能力の目安だった頃のコンピューターなら そうだな☆」
「 機械学習の頃のコンピューターの マルチ・コア・プログラミング なら
コア数を増やすことに どんな意味が出てくるの?」
並行性
Rust by Example
Fearless Concurrency
「 まず 並行処理 を理解しようぜ☆ そのあと 並列処理 を考えればいい☆」
「 データ・レース ができるようなプログラムは書けない、とのことだぜ☆
デッド・ロックはする☆」
「 とりあえず スレッドを作るプログラムを書いてみようぜ☆」
Test:
/**
* cargo new ep1
* cd C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1
* cargo run
*
* [並行性](https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/concurrency.html)
*/
use std::thread;
fn main() {
thread::spawn(|| {
println!("Hello from a new thread!");
});
println!("Hello from a main thread!");
}
Output:
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
新しいクロスプラットフォームの PowerShell をお試しください https://aka.ms/pscore6
PS C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust> cd C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1
PS C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1> cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target\debug\ep1.exe`
Hello from a main thread!
thread '<unnamed>' panicked at '
PS C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1>
PS C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1> cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target\debug\ep1.exe`
Hello from a main thread!
Hello from a new thread!
「 実行すると、うまく行くときと、うまく行かないときがある☆」
「 これは、スレッドを作成する前に、メイン・スレッドが終わってしまっているんだぜ☆
メイン・スレッドが すぐ終わらないよう、20ミリ秒 待たせてみようぜ☆?」
Test:
/**
* cargo new ep1
* cd C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1
* cargo run
*
* [並行性](https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/concurrency.html)
*/
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
println!("Hello from a new thread!");
});
println!("Hello from a main thread!");
thread::sleep(Duration::from_millis(20));
}
「 スレッドは値を返すことも できるようだぜ☆ やってみようぜ☆」
Test:
/**
* cargo new ep1
* cd C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1
* cargo run --example return
*
* [並行性](https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/concurrency.html)
*/
use std::thread;
fn main() {
let handle = thread::spawn(|| {
"Hello from a new thread!"
});
println!("Main | Child said: {}", handle.join().unwrap());
}
Output:
PS C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1> cargo run --example return
Compiling ep1 v0.1.0 (C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1)
Finished dev [unoptimized + debuginfo] target(s) in 0.52s
Running `target\debug\examples\return.exe`
Main | Child said: Hello from a new thread!
「 .join()
メソッドが スレッドが終わるまで待っているのかだぜ☆?」
Test
/**
* cargo new ep1
* cd C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1
* cargo build --example data-race-1
* cargo run --example data-race-1
*
* [並行性](https://doc.rust-jp.rs/the-rust-programming-language-ja/1.6/book/concurrency.html)
*/
use std::thread;
use std::time::Duration;
fn main() {
let mut data = 1;
let handle = thread::spawn(move || {
data += 1;
println!("Child | data: {}", data);
});
handle.join().unwrap();
println!("Main | data: {}", data);
thread::sleep(Duration::from_millis(50));
}
Output:
PS C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1> cargo run --example data-race-1
Compiling ep1 v0.1.0 (C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1)
Finished dev [unoptimized + debuginfo] target(s) in 0.41s
Running `target\debug\examples\data-race-1.exe`
Child | data: 2
Main | data: 1
「 子スレッドの中の data はコピーなのだろうか☆ メイン・スレッドに影響がないぜ☆」
「 親スレッドから 子スレッドへ 初期値を渡せるだけで、
子スレッドの中で変更しても 親スレッドには影響がないんじゃないか☆?」
「 子スレッドで行った変更を、親スレッドが知ることができなかったら、嬉しくないんじゃない?」
「 子スレッドが終わるまで .join()
で待って 返り値を取ったらどうだぜ☆?」
Test:
/**
* cargo new ep1
* cd C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1
* cargo build --example channel
* cargo run --example channel
*
* [メッセージ受け渡しを使ってスレッド間でデータを転送する](https://doc.rust-jp.rs/book/second-edition/ch16-02-message-passing.html)
*/
use std::thread;
use std::sync::mpsc;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
});
let received = rx.recv().unwrap();
// 値は{}です
println!("Main | Got: {}", received);
}
Output:
PS C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1> cargo run --example channel
Compiling ep1 v0.1.0 (C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1)
Finished dev [unoptimized + debuginfo] target(s) in 0.83s
Running `target\debug\examples\channel.exe`
Main | Got: hi
「 子スレッドから、親スレッドに 値を返すことは できるみたいだな☆」
Test:
/**
* cargo new ep1
* cd C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1
* cargo build --example channel-2
* cargo run --example channel-2
*
* [メッセージ受け渡しを使ってスレッド間でデータを転送する](https://doc.rust-jp.rs/book/second-edition/ch16-02-message-passing.html)
*/
use std::thread;
use std::sync::mpsc;
fn main() {
let (childEnter, childExit) = mpsc::channel();
let (mainEnter, mainExit) = mpsc::channel();
let childHandle = thread::spawn(move || {
let mut childBall = 1;
childEnter.send(childBall).unwrap();
childBall = mainExit.recv().unwrap();
println!("Child | Expected: 11, Got: {}.", childBall);
childBall += 100;
childEnter.send(childBall).unwrap();
childBall = mainExit.recv().unwrap();
println!("Child | Expected: 1111, Got: {}, Finished.", childBall);
});
let mut mainBall = childExit.recv().unwrap();
println!("Main | Expected: 1, Got: {}.", mainBall);
mainBall += 10;
mainEnter.send(mainBall).unwrap();
mainBall = childExit.recv().unwrap();
println!("Main | Expected: 111, Got: {}.", mainBall);
mainBall += 1000;
mainEnter.send(mainBall).unwrap();
childHandle.join().unwrap();
println!("Main | Finished.");
}
Output:
PS C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1> cargo run --example channel-2
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running `target\debug\examples\channel-2.exe`
Main | Expected: 1, Got: 1.
Child | Expected: 11, Got: 11.
Main | Expected: 111, Got: 111.
Child | Expected: 1111, Got: 1111, Finished.
Main | Finished.
Test:
/**
* cargo new ep1
* cd C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1
* cargo build --example channel-3
* cargo run --example channel-3
*
* [メッセージ受け渡しを使ってスレッド間でデータを転送する](https://doc.rust-jp.rs/book/second-edition/ch16-02-message-passing.html)
*/
use std::thread;
use std::sync::mpsc;
fn main() {
// 2つの方向。
let (child1Enter, child1Exit) = mpsc::channel();
let (child2Enter, child2Exit) = mpsc::channel();
let (mainEnter1, mainExit1) = mpsc::channel();
let (mainEnter2, mainExit2) = mpsc::channel();
let child1Handle = thread::spawn(move || {
let mut childBall = mainExit1.recv().unwrap();
println!("Child1 | Expected: 1, Got: {}.", childBall);
childBall += 10;
child1Enter.send(childBall).unwrap();
childBall = mainExit1.recv().unwrap();
println!("Child | Expected: 11111, Got: {}, Finished.", childBall);
childBall += 100000;
child1Enter.send(childBall).unwrap();
});
let child2Handle = thread::spawn(move || {
let mut childBall = mainExit2.recv().unwrap();
println!("Child | Expected: 111, Got: {}.", childBall);
childBall += 1000;
child2Enter.send(childBall).unwrap();
childBall = mainExit2.recv().unwrap();
println!("Child | Expected: 1111111, Got: {}, Finished.", childBall);
childBall += 10000000;
child2Enter.send(childBall).unwrap();
});
let mut mainBall = 1;
mainEnter1.send(mainBall).unwrap();
mainBall = child1Exit.recv().unwrap();
println!("Main | Expected: 11, Got: {}.", mainBall);
mainBall += 100;
mainEnter2.send(mainBall).unwrap();
mainBall = child2Exit.recv().unwrap();
println!("Main | Expected: 1111, Got: {}.", mainBall);
mainBall += 10000;
mainEnter1.send(mainBall).unwrap();
mainBall = child1Exit.recv().unwrap();
println!("Main | Expected: 111111, Got: {}.", mainBall);
mainBall += 1000000;
mainEnter2.send(mainBall).unwrap();
mainBall = child2Exit.recv().unwrap();
println!("Main | Expected: 11111111, Got: {}.", mainBall);
child1Handle.join().unwrap();
child2Handle.join().unwrap();
println!("Main | Finished.");
}
Output:
PS C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1> cargo run --example channel-3
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `target\debug\examples\channel-3.exe`
Child1 | Expected: 1, Got: 1.
Main | Expected: 11, Got: 11.
Child | Expected: 111, Got: 111.
Main | Expected: 1111, Got: 1111.
Child | Expected: 11111, Got: 11111, Finished.
Main | Expected: 111111, Got: 111111.
Child | Expected: 1111111, Got: 1111111, Finished.
Main | Expected: 11111111, Got: 11111111.
Main | Finished.
「 親1つ、子2つでも キャッチボールできてるような 結果は返してきているぜ☆」
「 じゃあ コンピューター囲碁サーバーでも、コンピューター将棋サーバーでも 作れるな☆」
「 これはまだ マルチ・スレッド・プログラミング(並行性) だぜ☆
マルチ・コア・プログラミング(並列性) をするには 通信も必要だぜ☆」
「 TCP/IP 通信をちらっと見返してきたら むずかしかったんで、
もう少し マルチ・スレッド・プログラミングを練習しようぜ☆?」
「 じゃあ 自然数の偶数 を打鍵したら 子スレッド1が 2倍した数を メッセージとともに返してきて、
自然数の奇数 を打鍵したら 子スレッド2 3倍した数を メッセージとともに返してくるように
しましょう」
「 標準入力から打鍵した文字列を取得するのは コンピューター将棋で作ったことがあるぜ☆」
Test:
/**
* cargo new ep1
* cd C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1
* cargo check --example input
* cargo build --example input
* cargo run --example input
*/
use std::io;
fn main() {
let mut line = String::new();
// コマンド プロンプトからの入力があるまで待機します。
io::stdin()
.read_line(&mut line)
.expect("info Failed to read_line"); // OKでなかった場合のエラーメッセージ。
// 末尾の 改行 を除きます。前後の空白も消えます。
line = line.trim().parse().expect("info Failed to parse");
println!("Read | {}", line);
}
Output:
PS C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1> cargo run --example input
Compiling ep1 v0.1.0 (C:\Users\むずでょ\OneDrive\ドキュメント\practice-rust\concurrency\ep1)
Finished dev [unoptimized + debuginfo] target(s) in 0.57s
Running `target\debug\examples\input.exe`
hello
Read | hello
<次の記事へ>
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント