Select in Elixir
Our example demonstrates the use of receive, which allows us to wait on multiple message operations. Combining processes and message passing with receive is a powerful feature of Elixir.
defmodule Select do
def run do
# For our example we'll receive from two processes.
pid1 = spawn(fn -> send_after_delay("one", 1000) end)
pid2 = spawn(fn -> send_after_delay("two", 2000) end)
# Each process will send a message after some amount
# of time, to simulate e.g. blocking operations
# executing in concurrent processes.
# We'll use `receive` to await both of these messages
# simultaneously, printing each one as it arrives.
for _ <- 1..2 do
receive do
{:msg, pid, msg} when pid == pid1 ->
IO.puts("received #{msg}")
{:msg, pid, msg} when pid == pid2 ->
IO.puts("received #{msg}")
end
end
end
defp send_after_delay(msg, delay) do
:timer.sleep(delay)
send(self(), {:msg, self(), msg})
end
end
Select.run()We receive the values “one” and then “two” as expected.
$ elixir select.exs
received one
received twoNote that the total execution time is only ~2 seconds since both the 1 and 2 second delays execute concurrently.
real 0m2.245sIn this Elixir version:
- We use
spawnto create new processes, which are similar to goroutines in their lightweight nature. - Instead of channels, we use Elixir’s built-in message passing system.
- The
receiveblock is used to wait for and handle messages, similar to theselectstatement in the original example. - We use pattern matching in the
receiveblock to differentiate between messages from different processes. - The
:timer.sleep/1function is used to introduce delays, similar totime.Sleepin the original.
This example showcases Elixir’s concurrency model, which is based on the Actor model, providing a different but equally powerful approach to concurrent programming compared to Go’s goroutines and channels.
Comments powered by Disqus