LoginSignup
17
2

More than 1 year has passed since last update.

簡単Elixirシリーズ ~ プロセスを知ろう② ~

Last updated at Posted at 2022-12-24

簡単Elixirシリーズ

~ プロセスを知ろう② ~

この記事は「Elixir Advent Calendar 2022」21日目の記事です
東京にいるけどfukuokaexのYOSUKEです。

簡単 Elixirシリーズでは小ネタをサクッと書いていこう。というコンセプトで作っていきます。

今回は、プロセスについて公式ドキュメントを見ながらサクッと解説の第2段です。

さて、前回の記事の続きものです、ちなみに前回の記事はこちらです。

今回は、Elixirのプロセスをさらに知る為に、例と共にさらに理解を深めていきたいと思います。

まずは、callに文字列を出力する無銘関数を作成。 そこに self()関数で自分のプロセスIDを出力するようにします。
 spawn(call)でcallを呼び出しプロセスを生み出します。生み出されたプロセスは、呼ばれた関数を実行します。
実行が終わったら、このプロセスは終了します。
ここでは、pidに生み出されたプロセスIDを束縛しておき、その後 Process.alive?(pid)でこのプロセスが生きてるか確認しています。
当然、実行後すぐにプロセスが終了しているので、falseが返ってきます。

iex()> call = fn -> IO.puts "process id is #{inspect(self())}." end
#Function<45.65746770/0 in :erl_eval.expr/5>
iex()> pid = spawn(call)
process id is #PID<0.112.0>.
#PID<0.112.0>
Process.alive?(pid)
false

プロセスのライフサイクルが何となく理解できたでしょうか?
次は、メッセージ機能について例えを利用して見ていきます。

defmodule MyProcess do
  def await_receive_msg(x, y) do
    IO.puts "プロセス #{inspect(self())}, メッセージ待ち中"
    receive do
      "Go" -> IO.puts "x + y = #{x + y}"
      "Quit" -> IO.puts "計算をやめます。"
      _ -> IO.puts "なんか別のメッセージが送られてきました"
    end
    IO.puts "プロセス #{inspect(self())} は実行し終えたので終了します。"
  end
end

例えば、こんな関数を書いておきます。

実行時にはspwan()を利用して、PIDを取得し、 PID毎に send(pid, "Quit"}などとして
メッセージを送って関数の実行をしているのが見えます。

iex(1)> pid = spawn(MyProcess, :await_receive_msg, [2, 1]) 
#PID<0.111.0>
プロセス #PID<0.111.0>, メッセージ待ち中
iex(2)> pid2 = spawn(MyProcess, :await_receive_msg, [3, 4])
プロセス #PID<0.113.0>, メッセージ待ち中
#PID<0.113.0>
iex(3)> Process.alive? pid                                 
true
iex(4)> Process.alive? pid2
true
iex(5)> send(pid, "Quit")                                  
計算をやめます。
プロセス #PID<0.111.0> は実行し終えたので終了します。
"Quit"
iex(6)> Process.alive? pid 
false
iex(7)> Process.alive? pid2
true
iex(8)> send(pid2, "Go")   
"Go"
7       
プロセス #PID<0.113.0> は実行し終えたので終了します。
iex(9)> Process.alive? pid2
false

このコードをさらに改良して、実行後にまた自分自身を呼び出すように書き換えて見ます。

defmodule MyProcess do
  def await_receive_msg() do
    IO.puts "プロセス #{inspect(self())}, メッセージ待ち中"
    receive do
      {x, y} -> IO.puts "x + y = #{x + y}"
                await_receive_msg()
      "Quit" -> IO.puts "計算をやめます。"
                await_receive_msg()
      _ -> IO.puts "なんか別のメッセージが送られてきました"
                await_receive_msg()
    end
  end
end

実行してみます。 計算の引数を msg として受けつけるように変更した事に注意してください。

iex()> pid = spawn(MyProcess, :await_receive_msg, [])      
プロセス #PID<0.140.0>, メッセージ待ち中
#PID<0.140.0>
iex(16)> send(pid, "Quit")                             
計算をやめます。
プロセス #PID<0.140.0>, メッセージ待ち中
"Quit"
iex()> send(pid, {1, 3})
x + y = 4
{1, 3}
プロセス #PID<0.140.0>, メッセージ待ち中
iex()> send(pid, [1,2]) 
なんか別のメッセージが送られてきました
[1, 2]
プロセス #PID<0.140.0>, メッセージ待ち中

プロセスが終了せずに状態まちをするようになりました。

さて、ここまで来ると、状態を保持する例も見て見たくなりますね。が、長くなるので、それは 第3段にまとめていきたいと思います。

17
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
2