How to implement your own :timer.sleep in Elixir

Elixir has :timer.sleep(ms), a function which allows you to pause a process’s execution for an arbitrary number of milliseconds.

We can implement the same using messages and a timeout in the following ways.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
defmodule SleepTimeout do
def sleep(milliseconds) do
# use a receive block with no matching blocks and an after block
# which times out after the input number of milliseconds
receive do
after
milliseconds ->
:ok
end
end
end

defmodule SleepMsg do
def sleep(milliseconds) do
# create a unique ref, so that we don't stop on any random `:timeout` message.
ref = make_ref()
# schedule a message to be sent to ourselves in the input number of milliseconds
Process.send_after(self(), {:timeout, ref}, milliseconds)

receive do
# wait for our message to arrive
{:timeout, ^ref} ->
:ok
end
end
end

{microseconds, _} = :timer.tc(fn -> SleepTimeout.sleep(1000) end)
IO.puts("slept for #{round(microseconds / 1000)} microseconds")
# => slept for 1000 microseconds


{microseconds, _} = :timer.tc(fn -> SleepMsg.sleep(1000) end)
IO.puts("slept for #{round(microseconds / 1000)} microseconds")
# => slept for 1001 microseconds

You may ask, what is the frigging point of all of this when we have :timer.sleep? Well, there is no point. This was just a fun little exercise :D


I am currently working on LiveForm which makes setting up contact forms on your website a breeze.