tomthestorm

tomthestorm

Why GenServer.call is synchronous?

Hi, I try understand GenServer .
Why GenServer.call is synchronous ? I want to get, in asynchronous way, information about state of the pid, but I can’t.
For example if I send 1000 of GenServer.call(pid,:get) via :

[ Task.await(Task.async(fn → Genserver.call(pid,:get) end)) , [ Task.await(Task.async(fn → Genserver.call(pid,:get) end)) , … , … ]

when I get the last one I have to wait 999 times.

Maybe it is stupid question , but for me GenServer.call should be asynchronous because we want read state and GenServer.cast should be synchronous cause we modify the state (and we should lock state during modification) .
But the situation is opposite and I don’t understand why .
Thanks in advance for answer .

Most Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

There are two minor misconceptions here: call vs cast is not about read vs write. You can (and usually should) modify via call, and you often use call to read too. Call vs cast is literally about whether you as the client want to communicate async vs sync.

This becomes clearer if you think about the mechanism of communication: message passing. All message passing is async, so if you send a message to the genserver to read OR write and you want to know the result, the only way you can do so is to wait around for a reply message from the genserver. This is exactly what call does. If you want to write and you don’t care about the result, or if you want to tell the genserver to send you a reply and you’ll look at it later, you can consider cast.

The second misconception is that the genserver is some state that can be read directly by the client. As noted, all communication between processes is via message passing, and so if clients want to read a genserver, the genserver needs to send them a message. Genservers, like all processes, are single threaded, and so the message sending happens one after the next.

11
Post #4
sztosz

sztosz

Cast and call are not about whether we read or modify the state, but do we wan’t to wait for the response, and do nothing or are we not going to wait for the response (we don’t care about the response at all).

Cast and call both can modify state.

Call is synchronous by nature, because it hast to send a response for which calling process await.

And beside that messages in GenServer are read sequentially IIRC, so any computation done based on message are done sequentially too.

peerreynders

peerreynders

For some background this topic may be of some interest:

This may already be an indication that you are solving your problem in a less than optimal way in a process-oriented environment (there simply isn’t enough detail to know whether this is in fact true).

More often than not process state exists to enable the process to enact some sort of protocol in concert with other processes rather than the process simply acting as a container-of-state to be queried.

To a certain degree this has been a problem in some object-oriented designs and can be even more a problem with process-oriented solutions.

Some of my posts around “Tell, don’t Ask”:

You wouldn’t write code like that anyway. At the very least you would organize it more like:

funs = [fn -> Genserver.call(pid,:get) end, fn -> Genserver.call(pid,:get) end, … , … ]
tasks = Enum.map(funs, &Task.async/1)
results = Enum.map(tasks, &Task.await/2)

or

funs = [fn -> Genserver.call(pid,:get) end, fn -> Genserver.call(pid,:get) end, … , … ]
results =
  funs
  |> Enum.map(&Task.async/1)
  |> Enum.map(&Task.await/2)

The idea being that you first launch all the tasks and only then you start waiting on them (in this particular case it wouldn’t make much of a difference as you are waiting on the same process anyway).

And ideally you would be using Task.Supervisor.async_stream/6 anyway, as that gives you better control of the level of concurrency that may be reasonable under the circumstances.

Where Next?

Popular in Questions Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
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
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
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
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New

Other popular topics Top

Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31194 112
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

We're in Beta

About us Mission Statement