dwyl / dwyl/learn-elixir

Concurrency related question

Open
#165 4 comments 1 reaction 0 assignees View on GitHub
Dominant language
Elixir
Stars
1.7k
Forks
112
PR merge metrics
No merged PRs in 30d

Description

Hi 😊

Thank you very much for a great introduction to Elixir!

I got a little bit stuck at ["Concurrency" section](https://github.com/dwyl/learn-elixir#concurrency).
I would be more than happy if you could explain me some details.

The `Factorial.spawn` function is implemented like this:
```
def spawn(n) do
1..n
|> Enum.chunk_every(4)
|> Enum.map(fn(list) ->
spawn(Factorial, :_spawn_function, [list])
|> send(self())

receive do
n -> n
end
end)
|> calc_product()
end
```

Each chunk is being processed by `Enum.map` function. The processing for each chunk goes like this:
1) create a new process (+ pass a function and the current chunk to be processed)
2) send a message with the main process's PID to newly created process (newly created process receives the message and starts calculations)
3) wait until the process responds with a calculated result for the current chunk.

As far as I understand, iterations of `Enum.map` are executed sequentially. On each iteration we spawn a process and then wait until it responds with a calculated result. Thus, it looks like, even though we utilize processes, the calculations are still done sequentially.

Initially, I thought that this modified implementation would execute faster:
```
def spawn_n_go(n) do
1..n
|> Enum.chunk_every(4)
|> Enum.map(fn(list) -> # create all the processes and start the calculations
spawn(Factorial, :_spawn_function, [list])
|> send(self())
end)
|> Enum.map(fn (_) -> # wait for each process to finish calculations and send the response
receive do
n -> n
end
end)
|> calc_product()
end
```
, because firstly it starts all the calculations and secondly it waits for all of them to finish (not one-by-one).

However, what surprised me, the execution of both versions on my machine took almost the same time. The initial version even executed a little bit faster. I tried experimenting with the input values, but the results were still the same.

This is where I got totally confused 😢

My only guess is perhaps BEAM is able to optimize the execution of `Enum.map` and start the next iteration while it waits for the result from `receive` macro... But that would be documented in the docs I guess. I haven't found anything like this.

Could you please provide me with some information on how this is possible (perhaps some docs or articles), so as I could understand this part better? If I am wrong, please correct me.

Maybe this information would be also useful for other readers.

Thank you!

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.