defmodule SyncCallonAsync do use GenServer def start_link do GenServer.start_link(__MODULE__, [], name: __MODULE__) end def init(_) do {:ok, %{pending: []}} end def sync do GenServer.call(__MODULE__, :sync) end def handle_call(:sync, {pid, _} = from, %{pending: pend} = state) do mref = Process.monitor(pid) dispatch_req(from) {:noreply, %{state | pending: [{from, mref}| pend]}} end def dispatch_req(from) do current = self() spawn(fn -> Process.sleep(1000) send current, {:delayed_reply, from, :done} end) end def handle_info(:timeout, state) do {:noreply, state} end def handle_info({:delayed_reply, from, reply}, %{pending: pend} = state) do case List.keytake(pend, from, 0) do {{_from, mref}, rest} -> Process.demonitor(mref) GenServer.reply(from, reply) {:noreply, %{state | pending: rest}} false -> {:noreply, state} end end end defmodule Run do def measure(function) do function |> :timer.tc |> elem(0) |> Kernel./(1_000_000) end def run_for(times \\ 10) do SyncCallonAsync.start_link 1..times |> Enum.each(fn (_) -> Task.async(fn -> measure(&SyncCallonAsync.sync/0) |> IO.inspect end) end) end end