dopatraman
What do GenServers offer over Tasks?
I’m looking for clarity on the benefits of GenServers. At first I thought they could be used to process asynchronous work via handle_case, but it seems like the popular literature, some by Jose himself, advocates against using casts in favor of the synchronous call. If GenServers are meant to be used to handle synchronous code, what’s the point? I have trouble how I’d benefit more by using them over a Task.
Consider the following classic breakfast scenario. To have breakfast, I need to do the following things:
- Make toast
- Cook eggs
- Butter the toast
- Pour orange juice
- Plate the eggs and toast
- Eat
To do this, (1,3), 2, and 4 could be run as separate tasks. 5 could await 1, 2, and 3, and 6 could await 1-5:
oj_task = Task.async(fn -> pour_oj() end)
[
Task.async(fn -> make_toast() |> butter_toast end),
Task.async(fn -> make_eggs() end)
]
|> Enum.map(&Task.await/1)
plate_task = plate_eggs_and_toast()
[ oj_task, plate_task] |> Enum.map(&Task.await/1) |> eat()
How would I be able to do this via GenServers?
It’s possible that I’m missing some foundational understanding here. I just don’t see the utility of using call when a Task or cast would do the trick. Please help clarify. Thank you!
Most Liked
wojtekmach
Anything you can do with Task you can do with a GenServer and the reason is… Task is a GenServer!
As others have mentioned, tasks are all about performing some computation, it has some initial state, does the work and returns the result. It doesnt maintain state in the sense that you cannot really ask it what its state is until the Task finishes. Theres another abstraction worth mentioning and that is Agent. Agent is the opposite of Task, its all about state and hardly about compute. You can ask the Agent what it state is and ask it to update its state but there is not really any computation associated with it.
Given both Agent and Task are built on top of a GenServer, it needs to necessarily allow handling both the state and compute. And it sure does!
Oh, and since you have been using async/await, what async basically does is it spawns a process (spawning a process is always async) to do the work and when the work is done it will send the message to the calling process. All awat basically does it is just waiting on that message. Thats basically what GenServer.call does too, it sends the message and awaits response. The difference is after async but before await you can do more work in the caller which is different than GenServer.call which is just one invocation. Sometimes you need one and sometimes the other is most appropriate.
Hope it helps!
ityonemo
Unless I’m mistaken, Task is not built on top of GenServer:
It’s really a new addition to OTP that Elixir brings to the table.
A task is for any situation where you want to have OTP supervision for things that are simple, linear sets of actions. You should default to using Tasks over GenServers in the general case.
GenServers have re-entrant, nonlinear asynchronous, event flows driven by message-passing. They’re very complicated and actually rather disorganized, code-wise, in OTP. 99% of the time you probably shouldn’t use a GenServer. Important exceptions are:
- You’re handling a stateful communications protocol (like TCP or something higher level like DHCP which is stateful over a stateless protocol).
- You’re modeling something stateful in the real world (for example a VM, or a client’s web browser panel) and need a “smart caching layer”
- You’re modeling something virtual that needs to be stateful and respond specifically to messages with a nonlinear control flow (like a poker game)
gregvaughn
EVERY process is sequential. A Task is only processing the function given to it. A GenServer is taking one message at a time from its mailbox. call vs. cast does not change this. Call vs. cast is whether the caller is waiting for a response from the GenServer or not.
edit: Sorry I didn’t mean to reply to you directly @krstfk, just to the topic in general
Popular in Discussions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








