読者です 読者をやめる 読者になる 読者になる

undefined

bokuweb.me

ElixirですごいE本 10章


しばらく停止していたElixirの勉強、順番を入れ替えて10章から再開することにした。

すごいErlangゆかいに学ぼう!

すごいErlangゆかいに学ぼう!

10.4 さようなら、いままで魚をありがとう

プロセスを生成する

iex(1)> spawn fn -> 2 + 2 end
#PID<0.59.0>

http://elixir-lang.org/getting-started/processes.html#spawn

  • <0.59.0> はプロセス識別子
  • プロセスを表す任意の値
defmodule LearnProcess do
  def g(x), do: :timer.sleep 10, IO.puts x

  def start do
    Enum.each(Range.new(1, 10), fn(i) ->
      spawn fn -> IO.puts i end
    end)
  end
end

LearnProcess.start

- 結果

6
2
1
4
8
3
9
10
5
7
  • :をつけるとErlangの関数が呼べる
  • なのでio:formatもこんなふうに呼べる:io.format("Hello, world!~n")
iex(1)> self()
#PID<0.57.0>
iex(2)> Process.alive?(self())
true
iex(5)> self()
#PID<0.57.0>
iex(6)> exit(self())
** (exit) #PID<0.57.0> 
  • self()で現在のプロセスのpid
  • alive?で生存を確認
  • pid変わってない..

メッセージを送信する

iex(1)> send self(), {:hello, "world"}
{:hello, "world"}
iex(2)> send self(), "hello"
"hello"
iex(3)> send self(), "hello"
"hello"
iex(4)> flush()
{:hello, "world"}
"hello"
"hello"
:ok
iex(5)> flush()
:ok
  • send/2でメッセージ送信
  • flush/0はメールボックスにある全てのメッセージを表示し,空にする

メッセージを受信する

  • dolphin.ex
defmodule Dolphins do
  def dolphin1 do
    receive do
      :do_a_flip -> IO.puts "How about no?"
      :fish -> IO.puts "So long and thanks for all the fish"
      _ -> IO.puts "Heh, we're smarter than you humans."
    end
  end
end
iex(1)> c("dolphins.ex")
iex(2)> send self(), :fish
:fish
iex(3)> spawn(Dolphins.dolphin1)
So long and thanks for all the fish
** (ArgumentError) argument error
    :erlang.spawn(:ok)
  • 受け取れてるがargument errorでてる

こうか。spawn/3の第二引数はatom

iex(1)> dolphin = spawn(Dolphins, :dolphin1, [])
#PID<0.60.0>
iex(2)> send dolphin, "oh, hello dolphin!"
Heh, we're smarter than you humans.
"oh, hello dolphin!"
iex(3)> send dolphin, :fish
:fish
iex(4)> send dolphin, :fish
:fish
iex(5)> send dolphin, :fish
:fish

プロセス終了していない。

もしパターンにマッチするメッセージがメールボックスに無ければ,現在のプロセスはマッチするメッセージがくるまで待ち続けます.タイムアウトを指定することもできます

defmodule Dolphins do
  def dolphin1 do
    receive do
      :do_a_flip -> IO.puts "How about no?"
      :fish -> IO.puts "So long and thanks for all the fish"
      _ -> IO.puts "Heh, we're smarter than you humans."
    after
      1_000 -> IO.outs "nothing after 1s"
    end
  end
end
iex(11)> c("ch10.ex")
[Dolphins]
iex(12)> dolphin = spawn(Dolphins, :dolphin1, [])
#PID<0.132.0>
nothing after 1s
  • タイマーを付けてみる、1sメッセージがなければ終了
defmodule Dolphins do
  def dolphin1 do
    receive do
      :do_a_flip -> IO.puts "How about no?"
      :fish -> IO.puts "So long and thanks for all the fish"
      _ -> IO.puts "Heh, we're smarter than you humans."
    after
      1_000 -> IO.puts "nothing after 1s"
    end
  end

  def dolphin2 do
    receive do
      {:do_a_flip, from} -> send from, "How about no?"
      {:fish, from} -> send from, "So long and thanks for all the fish"
      _ -> IO.puts "Heh, we're smarter than you humans."
    end
  end
end
iex(1)> c("ch10.ex")
[Dolphins]
iex(2)> dolphin = spawn(Dolphins, :dolphin2, [])
#PID<0.68.0>
iex(3)> send(dolphin, {:do_a_flip, self()})
{:do_a_flip, #PID<0.57.0>}
iex(4)> flush()
"How about no?"
:ok
iex(5)> send(dolphin, {:fish, self()})
{:fish, #PID<0.57.0>}
iex(6)> flush()
:ok
  • タプルにpidを詰めて送信、送り返す
  • 送り返した後プロセス終了?
defmodule Dolphins do
  def dolphin3 do
    receive do
      {:do_a_flip, from} ->
        send(from, "How about no?")
        dolphin3
      {:fish, from} -> send(from, "So long and thanks for all the fish")
      _ ->
        IO.puts "Heh, we're smarter than you humans."
        dolphin3
    end
  end
end
iex(8)> dolphin = spawn(Dolphins, :dolphin3, [])
#PID<0.83.0>
iex(9)> send(dolphin, {:do_a_flip, self()})
{:do_a_flip, #PID<0.57.0>}
iex(10)> send(dolphin, {:do_a_flip, self()})
{:do_a_flip, #PID<0.57.0>}
iex(11)> send(dolphin, {:do_a_fl, self()})
Heh, we're smarter than you humans.
{:do_a_fl, #PID<0.57.0>}
iex(12)> flush()
"How about no?"
"How about no?"
:ok
iex(13)> send(dolphin, {:do_a_fl, self()})
Heh, we're smarter than you humans.
{:do_a_fl, #PID<0.57.0>}
iex(14)> send(dolphin, {:do_a_flip, self()})
{:do_a_flip, #PID<0.57.0>}
iex(15)> flush()
"How about no?"
:ok
iex(16)> send(dolphin, {:fish, self()})
{:fish, #PID<0.57.0>}
iex(17)> send(dolphin, {:do_a_flip, self()})
{:do_a_flip, #PID<0.57.0>}
iex(18)> flush()
"So long and thanks for all the fish"
:ok
iex(19)> flush()
:ok
iex(20)> send(dolphin, {:do_a_flip, self()})
{:do_a_flip, #PID<0.57.0>}
iex(21)> flush()
:ok
  • メッセージを送り返したあと再帰でメッセージ待機