Elixir 是面向并发的编程语言,基于 Erlang VM(BEAM)虚拟机。Elixir 能够非常简单地实现并发编程,它的并发模型是 actor 模型。
Spawn
创建一个新进程最简单的办法是使用spawn/1
,它接受一个匿名函数或命名函数作为参数
spawn/1
返回一个 PID(进程标识符)。生成的进程将执行给定的函数,并在函数完成后退出
iex> pid = spawn fn -> 1 + 2 end
#PID<0.44.0>
iex> Process.alive?(pid)
false
通过self/0
命令检索当前进程的 PID
iex> self()
#PID<0.41.0>
iex> Process.alive?(self())
true
异步运行函数,可以用spawn/3
defmodule Example do
def add(a, b) do
IO.puts(a + b)
end
end
iex> spawn(Example, :add, [2, 3])
5
#PID<0.80.0>
消息传递(send 和 receive)
我们可以通过send/2
发送信息到进程,通过receive/1
接收。
iex> send self(), {:hello, "world"}
{:hello, "world"}
iex> receive do
...> {:hello, msg} -> msg
...> {:world, msg} -> "won't match"
...> end
"world"
receive/1
支持哨兵子句和case/2
等子句。receive/1
支持超时时间
iex> receive do
...> {:hello, msg} -> msg
...> after
...> 1_000 -> "nothing after 1s"
...> end
"nothing after 1s"
一个完整的例子
defmodule Example do
def listen do
receive do
{:ok, "hello"} -> IO.puts("World")
end
listen()
end
end
iex> pid = spawn(Example, :listen, [])
#PID<0.108.0>
iex> send pid, {:ok, "hello"}
World
{:ok, "hello"}
iex> send pid, :ok
:ok
进程链接(Links)
spwan_link/1
当程序崩溃的时候,spwan
就会有问题。父进程不知道子进程出错会导致程序异常。
def explode, do: exit(:kaboom)
iex> pid= spawn(Example, :explode, [])
#PID<0.143.0>
iex> pid = spawn_link(Example, :explode, [])
** (EXIT from #PID<0.102.0>) shell process exited with reason: :kaboom
Interactive Elixir (1.10.2) - press Ctrl+C to exit (type h() ENTER for help)
如果不希望链接的进程导致当前的进程跟着崩溃,可以使用Process.flag/2
函数捕获进程的错误退出。当捕获到被链接的进程发生错误退出时(trap_exit 设为 true), 就会收到像 {:EXIT, from_pid, reason}
这样的三元组形式的退出信号。
defmodule Example do
def explode, do: exit(:kaboom)
def run do
Process.flag(:trap_exit, true)
spawn_link(Example, :explode, [])
receive do
{:EXIT, _from_pid, reason} -> IO.puts("Exit reason: #{reason}")
end
end
end
iex> Example.run
Exit reason: kaboom
:ok
spawn/1
和spawn_link/1
是用于在 Elixir 中创建进程的基本原型。
尽管到目前为止我们已经完全使用它们,但大部分时间我们都会使用基于它们的抽象。让我们看看最常见的一个,称为任务。
任务(Tasks)
任务建立在 spawn 函数之上,以提供更好的错误报告和自省。
使用Task.start/1
和Task.start_link/1
来替代spawn/1
和spawn_link/1
。它们会返回{:ok,pid}
,而不仅仅是 PID。此外,Task
提供了方便的功能,如Task.async/1
和Task.await/1
参考:
https://github.com/KINGMJ/elixir-learning/blob/elixir-tutorial/lib/demo7.ex