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

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
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
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
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
LegitStack
I’m trying to make a websocket server in Phoenix or raw Elixir. I heard about gun, I think I could use cowboy, but since I’m not that sma...
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
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

Other popular topics Top

stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
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
Tee
can someone please explain to me how Enum.reduce works with maps
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
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
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
lucidguppy
I have a super simple question about elixir - how would I take a file like this foo bar baz and output a new file that enumerates th...
New

We're in Beta

About us Mission Statement