Part26:プロセス

凛「いよいよ並行プログラミングに突入にゃ!」
海未「Elixirの本領発揮ですね」
凛「まずは基礎知識としてプロセスの説明をするにゃ」

凛「いままで見てきたコードは、ぜんぶ1つのプロセスの中で動いてたんだよ。けどElixirでは、いーっぱいプロセスを作って、同時に処理を動かすことができるにゃ!」
希「psで見れるやつ?」
凛「とは違うにゃ。OSのプロセスとは別物みたいだよ」

凛「とりあえずプロセスを1つ作って動かしてみるにゃ」

凛「spawn関数を使うと新しいプロセスができて、引数で渡した関数が実行されるんだよ」
希「ここだけ見ると、あまり今までと変わらんね」
凛「まだまだこれからにゃ。このspawnが返すのはPIDっていうデータ型で、できたプロセスのIDが入ってるんだ。でね、このIDを使ってプロセスにアクセスできるんだよ」

凛「Process.is_alive?はプロセスが生きてるかどうかチェックする関数にゃ。ちなみにチェックが2回書いてあるのは、1回目だとまだプロセスが生き残ってることが多いからにゃ」
海未「実行が終了したときが寿命だとすれば、2行目の時点ですでに死んでいないとおかしいのではないでしょうか」
凛「今まで見てきたコードならその通りだけど、新しいプロセスは元のプロセスと並行で動くにゃ」
海未「ということは、2行目の時点ではまだ1行目のプロセスも動いている、ということですか?」
凛「うん。で、3行目くらいまで来るとだいたい実行終了して死ぬんだけど、このへんはPCの環境とかによって変わるからこの例を鵜呑みにしない方がいいにゃ」
希「厳密に見たかったら再帰で終了待機してみてもええかもね」

凛「プロセス同士でメッセージの送り合いができるんだ」

凛「新しいプロセスから元のプロセスにメッセージを送ってみたにゃ。sendが送信、receiveで受信だよ」
希「self()は元のプロセスかな」
凛「現在のプロセスのPIDが取れるにゃ。だから、それを送信先にしてsendを呼んでるんだよ」
海未「タプルの部分がメッセージの本文、ですか?」
凛「そうだけど、実はここはタプルでなくてもいいにゃ。どんな形でも送れるよ」
海未「receiveのパターンマッチで引っかかればいいのですね」
凛「そういうことにゃ」

凛「sendで送ったメッセージは受信側の”mailbox”に届いて、いつでもreceiveで受け取れるんだよ。receiveはmailboxにマッチするメッセージがなかったら、何か入ってくるまで待機するにゃ」
希「待つ時間って決まってるんやない?ほら、スコアマッチなら30秒とか」
凛「もちろんタイムアウトは指定できるにゃ」

凛「ところで、プロセスの中で例外吐いて死んでも、他のプロセスは意識的に監視してないと気付かないにゃ」

海未「何も出てきませんね」
凛「プロセス同士は独立してるから例外も伝わらないんだよ」

凛「spawnのかわりにspawn_linkを使うと、プロセス同士につながりができるにゃ」

凛「こうすると親プロセスと心中できるよ」
希「これ、親プロセス側でrescueとかcatchとかした方がええん?」
凛「ううん、これから出てくるOTPとかだと、プロセスを監視して死んだら再起動してくれたりするんだよ。だから、あまり気にしなくていいにゃ」
海未「そういえば、例外処理の時にもそんな話がありましたね」

凛「ここまでで見てきたプロセスは、処理を実行してすぐ死んじゃうだけだったけど、値とか設定をずっと持ってたりしたい場合もあるにゃ」
希「使い捨てじゃなくて、動き続けてほしいわけやね」
凛「そんなときは無限ループすればいいにゃ」

凛「超簡易スコアマッチメッセージサーバにゃ」
海未「隣の人フルコンします・・・うっ、頭が・・・」
希「あの人と当たるとプレッシャーきついんよなあ・・・」

凛「KVってモジュールが、メッセージを保管するプロセスの実装にゃ。実のところただのマップで、データの入ったマップを引数にして再帰を続けてるんだよ」
海未「このプロセスはずっと動き続けるのですね」
凛「明示的に殺さない限りはずっと動いてるよ。でね、receiveのところを見ると、:getか:putで始まるタプルを受け取るようになってて、これはgetとかputとかいう命令だと思えばいいにゃ」
海未「その命令を含むメッセージを受け取ったら、対応する処理をする、と」
凛「getはマップから対応する値を探してメッセージ送信元に送り返して、putは受け取ったキーと値をマップに入れてるにゃ。つまり、メッセージを通してマップへの出し入れをするプロセスなんだよ」
希「そう考えると大したことしてへんな」

凛「Process.registerはプロセスに名前を付けてるにゃ。PIDじゃなくてここで付けた名前でメッセージを送れるようになるから便利だよ」

凛「最初の2つのプロセスは、サーバに名前と一言を送ってるにゃ」
希「これはサーバのマップに収まるんやね」
凛「その後の2つのプロセスは、名前を指定して一言を取ってきてるにゃ」
希「そうすると、さっきサーバに送ったやつが返ってくると」

凛「実際はこういう場合だと、各プレーヤーに1プロセス割り当てて、他のプレーヤーのメッセージ送信に反応してサーバから通知受け取ったりとかすると思うけど、作り込みすぎるとサンプルコードじゃなくなってくるから自重したにゃ」

海未「大勢で1つのシステムを使うときに有利になるのですね」
凛「Elixirがすごく得意な場面だよ」
希「すごく難しいんかと思ってたらそうでもないんやね」

凛「次回は希ちゃんがOTPの解説を始めてくれるはずにゃ」
希「んー、したら頑張ってみよかな」


LINEで送る
Pocket


返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です