Skip to content

Instantly share code, notes, and snippets.

@kevinkirkup
Created February 16, 2021 21:09
Show Gist options
  • Save kevinkirkup/dc9b15ea75001282e77e4e42eb24bbba to your computer and use it in GitHub Desktop.
Save kevinkirkup/dc9b15ea75001282e77e4e42eb24bbba to your computer and use it in GitHub Desktop.
Exercise 4.2
defmodule Exercise42 do
@moduledoc """
Documentation for `Exercise 4.2`.
"""
require IO
def sort(values) do
router = create_router()
Enum.each(values, fn v -> send(router, {:int, v}) end)
send(router, {:get_results, self()})
receive do
{:result, result} -> result
end
end
defp create_router() do
spawn(Exercise42, :router_init, [])
end
def router_init() do
# Create a process running worker_loop/1 for each integer in the range 1 - 9
workers = Enum.reduce(1..9, %{}, &Map.put_new(&2, &1, spawn(Exercise42, :worker_loop, [[]])))
router_loop(workers)
end
def router_loop(workers) do
receive do
{:int, n} ->
# Find the correct worker and send it a value message
send(workers[n], {:value, n})
router_loop(workers)
{:get_results, sender} ->
results =
Map.keys(workers)
# Sort workers in ascending order so the final list is in the correct order
|> Enum.sort()
# Ask each worker for their values
|> Enum.flat_map(&get_worker_results(workers[&1]))
IO.inspect(results, label: "Router Loop")
# Send results to sender and exit
send(sender, {:result, results})
end
end
def get_worker_results(worker_pid) do
# Send worker a message asking for results
send(worker_pid, {:get_results, self()})
# Receive worker's reply, tell it to shut down and return the worker's values
receive do
{:results, values} ->
send(worker_pid, {:shutdown})
values
end
end
def worker_loop(values) do
receive do
# Handle messages adding a new value
{:value, n} ->
worker_loop([n | values])
# Handle messages requesting values
{:get_results, sender} ->
send(sender, {:results, values})
worker_loop(values)
# Handle shut down message
{:shutdown} ->
exit(:normal)
end
end
def random_ints(n), do: random_ints(n, [])
defp random_ints(0, accum), do: accum
defp random_ints(n, accum) do
random_ints(n - 1, [:random.uniform(9) | accum])
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment