プロ

プロセス の Elixir

5個の演習

プロセスについて

Elixirでは、すべてのコードはプロセスの中で実行されます。Elixirのプロセスには、次のような特徴があります。

_何百_ものプロセスを動かすElixirアプリは珍しくありませんが、特にそれがライブラリであれば、新しいプロセスを明示的に一切作らないアプリも普通にあります。

プロセスの作成

デフォルトでは、関数はそれを呼び出したのと同じプロセスの中で実行されます。ある関数を新しいプロセスで明示的に実行したいときは、spawnを使います。

  • spawn/1は、そのまま実行する関数を引数に取ります。

    spawn(fn -> 2 + 2 end)
    # => #PID<0.125.0>
    
  • spawn/3は、実行する関数を、モジュール名、関数名(アトム)、その関数に渡す引数のリストで指定します。

    spawn(String, :split, ["hello there", " "])
    # => #PID<0.113.0>
    
    • この3つのデータの組は、MFA(Module、Function、Arguments)と呼ばれることがよくあります。
  • プロセスは、その関数の実行が終わるとすぐに終了します。

  • プロセスがまだ_生きている_(実行中である)かどうかは、Process.alive?/1で確認できます。

    pid = spawn(fn -> 2 + 2 end)
    Process.alive?(pid)
    # => false
    

メッセージ

プロセス同士が直接情報を共有することはありません。プロセスはデータを共有するために_メッセージを送り_ます。この並行処理のパターンは、アクターモデルと呼ばれます。

  • プロセスにメッセージを送るには、send/2を使います。

    send(pid, :hello)
    
    • メッセージは、送られた順に受信側の_メールボックス_に届きます。
    • sendは、メッセージが受信されたかどうかも、受信側がまだ生きているかどうかも確認しません。
  • メッセージはどのような型でもかまいません。

  • 現在のプロセスに送られたメッセージは、receive/1で受け取ることができます。

    • メッセージに対してパターンマッチを行う必要があります。
    • receiveは、指定したいずれかのパターンに一致するメッセージがプロセスのメールボックスに入るまで待ちます。
      • デフォルトでは無期限に待ちますが、afterブロックを使ってタイムアウトを指定できます。
    • 読み取られたメッセージはプロセスのメールボックスから取り除かれます。読み取られていないメッセージは、そのまま無期限に残ります。
      • 読み取られていないメッセージがたまってメモリ不足にならないよう、receive/1には必ずすべてに一致する_節を書いてください。
    receive do
      {:ping, sender_pid} -> send(sender_pid, :pong)
      _ -> nil
    after
      5000 ->
        {:error, "No message in 5 seconds"}
    end
    

受信ループ

複数のメッセージを受け取りたいときは、receive/1を再帰的に呼び出す必要があります。receive/1を呼び出し、メッセージに対して何らかの処理を行い、さらにメッセージを待つために自分自身を呼び出す再帰関数(たとえばloopという名前の関数)を実装するのは、よくあるパターンです。あるreceive/1の呼び出しから次の呼び出しへ状態を持ち越したいときは、そのloop関数に引数を渡すことで実現できます。

def loop(state) do
  receive do
    :increment_by_one ->
      loop(state + 1)

    {:report_state, sender_pid} ->
      send(sender_pid, state)
      loop(state)

    :stop ->
      nil

    _ ->
      loop(state)
  end
end

実際には、この方法を直接使うことはほとんどありません。Elixirには、AgentモジュールやGenServerビヘイビアなど、どちらも受信ループの上に成り立つ並行処理の抽象化が用意されています。ただし、これらの抽象化を効率よく使いこなすには、基本をしっかり理解しておくことが欠かせません。

GitHubで編集 リンクは新しいウィンドウまたはタブで開きます

プロセスを学習する

練習はロックされています

プロセスを練習するには、あと4個の演習のロックを解除してください