Skip to content

Instantly share code, notes, and snippets.

@slashmili
Created December 14, 2016 10:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save slashmili/f3f9ea9a34039700c779c99f5b34dda5 to your computer and use it in GitHub Desktop.
Save slashmili/f3f9ea9a34039700c779c99f5b34dda5 to your computer and use it in GitHub Desktop.
Sample GenServer that provides sync call over async function
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment