zulkris

zulkris

Why sleep (Process.sleep or :timer.sleep) freed process messages?

Have code:

single_api_call = fn ->
  sleep_time = Enum.random(554..2944)
  Process.sleep(sleep_time) # this line affects results
  sleep_time
end

defmodule Worker do
  def start(fun) do
    pid = self()
    send(pid, {self(), fun.()})
  end
end

Enum.to_list(1..10)
|> Enum.map(
    fn _num ->
      spawn Worker, :start, [single_api_call]
    end)

Process.sleep(3000)
Process.info(self(), :messages) |> IO.inspect()

please see at line with Process.sleep.
Now code works this way:

[#PID<0.103.0>, #PID<0.104.0>, #PID<0.105.0>, #PID<0.106.0>, #PID<0.107.0>,
 #PID<0.108.0>, #PID<0.109.0>, #PID<0.110.0>, #PID<0.111.0>, #PID<0.112.0>]
{:messages, []}

messages is empty! why?

after deleting line with Process.sleep() it works fine:

[#PID<0.103.0>, #PID<0.104.0>, #PID<0.105.0>, #PID<0.106.0>, #PID<0.107.0>,
 #PID<0.108.0>, #PID<0.109.0>, #PID<0.110.0>, #PID<0.111.0>, #PID<0.112.0>]
{:messages,
 [
   {#PID<0.103.0>, 2049},
   {#PID<0.104.0>, 619},
   {#PID<0.105.0>, 2854},
   {#PID<0.106.0>, 2584},
   {#PID<0.107.0>, 706},
   {#PID<0.109.0>, 2700},
   {#PID<0.110.0>, 2397},
   {#PID<0.111.0>, 2303},
   {#PID<0.112.0>, 1863}
 ]}

Marked As Solved

joey_the_snake

joey_the_snake

Actually my bad. There is a bug in your code. The Worker is sending the message to itself instead of the main process. You have to do this

defmodule Worker do
  def start(pid, fun) do
    send(pid, {self(), fun.()})
  end
end

Enum.to_list(1..10)
|> Enum.map(
    fn _num ->
      spawn Worker, :start, [self(), single_api_call]
    end)

Also Liked

rvirding

rvirding

Creator of Erlang

Yes, back in the old days before multicore when there was only one scheduler we had very strict requirements that the system should NEVER block. So it is as @ChrisYammine says the scheduler forces processes to yield control, either after a fixed number of reductions (function calls), waiting for a message or timeout and other things. This is why you have never had to think about making sure a process doesn’t block the system. It can’t.

This of course just works in the same way with many schedulers.

There is a lot, A LOT, of effort put into the BEAM implementation to make this work efficiently and painlessly.

joey_the_snake

joey_the_snake

pure guessing, but maybe the number of cpus assigned to the docker container is too small and so the spawned tasks don’t get scheduled until after the main process is finished

rvirding

rvirding

Creator of Erlang

The reason is that in Worker.start/ the function defined in single_api_call is called before a message is sent. This is because that function is called when creating the message to be sent {self(), fun.()} and the send requires all ita arguments to be evaluated which means it waits until the function returns which is after it has slept.

dimitarvp

dimitarvp

I’ll be the guy to ask:

What is it that you’re truly aiming at?

There are good job queue / worker pool libraries, we can point you at some of them if you don’t want to roll your own.

bdarla

bdarla

As it is also recommended in the hex docs, using sleep shall be avoided.
If you want to use the first sleep to “simulate” something, leave it there for your testing.
However, the sleep of the parent process can be relaxed with a receive as suggested in the aforementioned Hexdocs, e.g. with a receive:

parent = self()
Task.start_link(fn ->
  do_something()
  send(parent, :work_is_done)
  ...
end)

receive do
  :work_is_done -> :ok
after
  # Optional timeout
  30_000 -> :timeout
end

In this example from Hexdocs, replace do_something with single_api_call and the Task with your Process.

Where Next?

Popular in Questions Top

albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lis...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
Mooodi
Given a string, how can I get access to its character by index? Enum.at("my_string", 2) doesn't work. Or rather, not char, but a substr...
New

Other popular topics Top

Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
chensan
I have a User schema with a :from_id field set to type :string: defmodule TweetBot.Repo.Migrations.CreateUsers do use Ecto.Migration ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New

We're in Beta

About us Mission Statement