166 lines
3.7 KiB
Elixir
166 lines
3.7 KiB
Elixir
defmodule Processes do
|
|
use Koans
|
|
|
|
@intro "Processes"
|
|
|
|
koan "You are a process" do
|
|
assert Process.alive?(self()) == ___
|
|
end
|
|
|
|
koan "You can ask a process to introduce itself" do
|
|
information = Process.info(self())
|
|
|
|
assert information[:status] == ___
|
|
end
|
|
|
|
koan "Processes are referenced by their process ID (pid)" do
|
|
assert is_pid(self()) == ___
|
|
end
|
|
|
|
koan "New processes are spawned functions" do
|
|
value = spawn(fn -> receive do
|
|
end
|
|
end)
|
|
|
|
assert is_pid(value) == ___
|
|
end
|
|
|
|
koan "Processes die when their function exits" do
|
|
fast_process = spawn(fn -> :timer.sleep(10) end)
|
|
slow_process = spawn(fn -> :timer.sleep(1000) end)
|
|
|
|
# All spawned functions are executed concurrently with the current process.
|
|
# You check back on slow_process and fast_process 50ms later. Let's
|
|
# see if they are still alive!
|
|
:timer.sleep(50)
|
|
|
|
assert Process.alive?(fast_process) == ___
|
|
assert Process.alive?(slow_process) == ___
|
|
end
|
|
|
|
koan "Processes can send and receive messages" do
|
|
send self(), "hola!"
|
|
|
|
receive do
|
|
msg -> assert msg == ___
|
|
end
|
|
end
|
|
|
|
koan "A process will wait forever for a message" do
|
|
wait_forever = fn ->
|
|
receive do
|
|
end
|
|
end
|
|
|
|
pid = spawn(wait_forever)
|
|
|
|
assert Process.alive?(pid) == ___
|
|
end
|
|
|
|
koan "Received messages are queued, first in first out" do
|
|
send self(), "hola!"
|
|
send self(), "como se llama?"
|
|
|
|
assert_receive ___
|
|
assert_receive ___
|
|
end
|
|
|
|
koan "A common pattern is to include the sender in the message, so that it can reply" do
|
|
greeter = fn ->
|
|
receive do
|
|
{:hello, sender} -> send sender, :how_are_you?
|
|
end
|
|
end
|
|
|
|
pid = spawn(greeter)
|
|
|
|
send pid, {:hello, self()}
|
|
assert_receive ___
|
|
end
|
|
|
|
def yelling_echo_loop do
|
|
receive do
|
|
{caller, value} ->
|
|
send caller, String.upcase(value)
|
|
yelling_echo_loop()
|
|
end
|
|
end
|
|
|
|
koan "Use tail recursion to receive multiple messages" do
|
|
pid = spawn_link(&yelling_echo_loop/0)
|
|
|
|
send pid, {self(), "o"}
|
|
assert_receive ___
|
|
|
|
send pid, {self(), "hai"}
|
|
assert_receive ___
|
|
end
|
|
|
|
def state(value) do
|
|
receive do
|
|
{caller, :get} ->
|
|
send caller, value
|
|
state(value)
|
|
{caller, :set, new_value} ->
|
|
state(new_value)
|
|
end
|
|
end
|
|
|
|
koan "Processes can be used to hold state" do
|
|
initial_state = "foo"
|
|
pid = spawn(fn ->
|
|
state(initial_state)
|
|
end)
|
|
|
|
send pid, {self(), :get}
|
|
assert_receive ___
|
|
|
|
send pid, {self(), :set, "bar"}
|
|
send pid, {self(), :get}
|
|
assert_receive ___
|
|
end
|
|
|
|
koan "Waiting for a message can get boring" do
|
|
parent = self()
|
|
spawn(fn -> receive do
|
|
after
|
|
5 -> send parent, {:waited_too_long, "I am impatient"}
|
|
end
|
|
end)
|
|
|
|
assert_receive ___
|
|
end
|
|
|
|
koan "Trapping will allow you to react to someone terminating the process" do
|
|
parent = self()
|
|
pid = spawn(fn ->
|
|
Process.flag(:trap_exit, true)
|
|
send parent, :ready
|
|
receive do
|
|
{:EXIT, _pid, reason} -> send parent, {:exited, reason}
|
|
end
|
|
end)
|
|
|
|
receive do
|
|
:ready -> true
|
|
end
|
|
|
|
Process.exit(pid, :random_reason)
|
|
|
|
assert_receive ___
|
|
end
|
|
|
|
koan "Parent processes can trap exits for children they are linked to" do
|
|
Process.flag(:trap_exit, true)
|
|
spawn_link(fn -> Process.exit(self(), :normal) end)
|
|
|
|
assert_receive {:EXIT, _pid, ___}
|
|
end
|
|
|
|
koan "If you monitor your children, you'll be automatically informed for their depature" do
|
|
spawn_monitor(fn -> Process.exit(self(), :normal) end)
|
|
|
|
assert_receive {:DOWN, _ref, :process, _pid, ___}
|
|
end
|
|
end
|