ヽ(´・肉・`)ノログ

How do we fighting without fighting?

すごいE本をElixirでやる(26)

第 11 章マルチプロセスについてもっと - 11.4 選択的受信 から

11.4 選択的受信

自分の欲しいメッセージにだけ反応することができる.

下のコードでは,まず priority が 10 より大きいものを全て処理してから,残りのものを処理している.

defmodule Multiproc do
  def important do
    receive do
      {priority, message} when priority > 10 ->
        [message | important()]
    after 0 ->
      normal()
    end
  end

  def normal do
    receive do
      {_, message} ->
        [message | normal()]
    after 0 ->
      []
    end
  end
end
Eshell V8.0.2  (abort with ^G)
Interactive Elixir (1.3.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> c("multiproc")
c("multiproc")
[Multiproc]
iex(2)> send(self, {15, :high})
send(self, {15, :high})
{15, :high}
iex(3)> send(self, {7, :low})
send(self, {7, :low})
{7, :low}
iex(4)> send(self, {1, :low})
send(self, {1, :low})
{1, :low}
iex(5)> send(self, {17, :high})
send(self, {17, :high})
{17, :high}
iex(6)> Multiproc.important()
Multiproc.important()
[:high, :high, :low, :low]
iex(7)>

選択的受信の落とし穴

選択的受信には、無視したメッセージがプロセスに大量にあると使えるメッセージを読み込む時間がどんどん長くなるという問題があります

このような受信が Erlang のパフォーマンスの問題の原因になる場合がよくあります。

必要のないメッセージを受け取っている理由を自問することです。

なるほど.メッセージキューに不要なメッセージを積まない.

さらにメールボックスの落とし穴

どんなメッセージも少なくとも1つの節に確実にマッチするような receive は Elixir だと

receive do
  (パターン1) -> (式1)
  (パターン2) -> (式2)
  (パターン3) -> (式3)
  unexpected ->
    IO.puts "unexpected message #{inspect unexpected}"
end

と書ける.

メッセージで優先度を扱う必要があって、catch-all 節のようなものを使えない場合、 min-heap (https://secure.wikimedia.org/wikipedia/en/wiki/ Min-heap)を実装するか、 あるいは、受信したメッセージすべてを gb_trees モ ジュール(第 9 章参照)を使ってダンプするほうがいい

なるほど.覚えておこう.