Goal
Elixirプロセスの基本的な使い方を習得する。
Dev-Environment
OS: Windows8.1
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4
Erlang: Eshell V6.4, OTP-Version 17.5
Elixir: v1.0.4
Wait a minute
Elixirのプロセスを使ってみます。
プロセスを生成したり、メッセージを送ってみたりします。
プロセスを生成したり、メッセージを送ってみたりします。
Stateでは、状態について学びます。
また、Agentについても少しやります。
また、Agentについても少しやります。
Index
Processes
|> For process in Elixir
|> Create process
|> Message process
|> Links
|> State
|> Extra
|> For process in Elixir
|> Create process
|> Message process
|> Links
|> State
|> Extra
For process in Elixir
Elixirでは全てのコードがプロセス内部で動いている。
特徴のまとめ・・・
- プロセス同士は独立している
- プロセスは並行で動作する
- メッセージパッシングでやり取りする
- OSのプロセスとは別
- メモリとCPUに大して軽量
分散処理や高可用性の構築に役立つそうです。
数千のプロセスを保持できるとか・・・素晴らしい!!
数千のプロセスを保持できるとか・・・素晴らしい!!
Create process
プロセスの生成について。
spawn/1について簡単なまとめ・・・
- 他のプロセスで実行する関数を受け取る
- PID(プロセス識別子)を返す
- 関数を実行したら死ぬ
プロセスを生成してみる。
iex> pid = spawn fn -> 1 + 1 end
#PID<0.58.0>
プロセスが生きているか確認してみる。
iex> Process.alive?(pid)
false
今のプロセス(PID)を取得してみる。
iex> self
#PID<0.56.0>
Message process
プロセス間でのメッセージをやり取りについて。
簡単なまとめ・・・
- send/2を使って送る
- receive/1を使って受け取る
- flush/0で全てのメッセージを表示して空にできる
実際に使ってみる。
メッセージのやり取りをしてみる。
iex> parent = self
iex> spawn fn -> send(parent, {:pid, self}) end
#PID<0.98.0>
iex> receive do
...> {:pid, pid} -> "receive pid = #{inspect pid}"
...> after
...> 1_000 -> "nothing after 1s"
...> end
"receive pid = #PID<0.98.0>"
Description:
以下の部分でメッセージがない場合のタイムアウトを設定している。
以下の部分でメッセージがない場合のタイムアウトを設定している。
...> after
...> 1_000 -> "nothing after 1s"
...> end
flush/0で表示させてみる。
iex> spawn fn -> send(parent, {:pid, self}) end
#PID<0.105.0>
iex> flush
{:pid, #PID<0.105.0>}
:ok
Links
spawn_link/1を経由させてみる。
また、プロセスの失敗を見てみる。
また、プロセスの失敗を見てみる。
簡単なまとめ・・・
- プロセスは独立している
- だから、他のプロセスに影響がない
- 伝播させるには、spawn_link/1を使う
- link/1で手動でも行える
- Supervisorがシステムの再起動をしてくれる
- さっさとクラッシュさせる方針が取れる
失敗させてみる。
iex> spawn fn -> raise "oops" end
#PID<0.58.0>
23:06:25.413 [error] Error in process <0.58.0> with exit
value: {#{'__exception__'=>true,'__struct__'=>'Elixir.RuntimeError',message=><<4 bytes>>},[{erlang,apply,2,[]}]}
spawn_link/1を使ってみる。
iex(1)> spawn_link fn -> raise "oops" end
23:28:23.819 [error] Error in process <0.58.0> with exit
value: {#{'__exception__'=>true,'__struct__'=>'Elixir.RuntimeError',message=><<4 bytes>>},[{erlang,apply,2,[]}]}
** (EXIT from #PID<0.56.0>) an exception was raised:
** (RuntimeError) oops
:erlang.apply/2
Interactive Elixir (1.0.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
State
アプリケーション設定や解析データなどの保持について。
実際に、elixir-lang - Processes - Stateのサンプルを試して経験してみます。
defmodule KV do
def start_link do
{:ok, spawn_link(fn -> loop(%{}) end)}
end
defp loop(map) do
receive do
{:get, key, caller} ->
send caller, Map.get(map, key)
loop(map)
{:put, key, value} ->
loop(Map.put(map, key, value))
end
end
end
実行してみる。
>iex kv.exs
iex> {:ok, pid} = KV.start_link
{:ok, #PID<0.62.0>}
iex> send pid, {:put, :hello, self}
{:put, :hello, #PID<0.60.0>}
iex> send pid, {:get, :hello, self}
{:get, :hello, #PID<0.60.0>}
iex> flush
#PID<0.60.0>
:ok
pidに名前を付けてみる。
(上記のpidを使っています)
(上記のpidを使っています)
iex> Process.register(pid, :kv)
true
iex> send :kv, {:get, :hello, self}
{:get, :hello, #PID<0.60.0>}
iex> flush
#PID<0.60.0>
:ok
ここら辺を上手く抽象化してくれているのがAgentらしい。
Extra
先ほどと、ほぼ同一の内容をAgentを使って少しだけやってみます。
iex> {:ok, pid} = Agent.start_link(fn -> %{} end)
{:ok, #PID<0.67.0>}
iex> Agent.update(pid, fn map -> Map.put(map, :pid, self) end)
:ok
iex> Agent.get(pid, fn map -> Map.get(map, :pid) end)
#PID<0.67.0>
Speaking to oneself
正直に言いますが、何に使えるのか自分の実力ではさっぱりです。
(パラレルダウンロード、平行で解析を流す・・・とかですかね?)
(パラレルダウンロード、平行で解析を流す・・・とかですかね?)
まぁ、プログラムっぽくて割と好きな内容でしたけど(笑)