zerogvt
Hi all,
I’ve been trying to wrap my head around this for a few days but I get more and more confused as I go. So I guess it’s time I ask for some help.
Say you want to implement next architecture: A process X is reading up a list of urls and spawns a process Yn for each one of them (imagine a web crawler for instance). Each Yn starts about its own thing (they don’t do the same calculations) and when it finishes off it has to call X back and tell it that it’s done. Meanwhile X is awaiting/listening and crossing off any done url of its list.
So far I’ve tried implementing X as an Agent (I need to keep state (a stack of urls) on it) and Yn as GenServers. Yet:
- if I try to kick
Yns with acall(synchronous) I cannot kick them off concurrently - if I kick them off with a
cast(asynchronously)Xwon’t wait and it exits whileYns are still active thus killing the whole tree (Note: I use escript to create an executable out of this. I do not run it all through iex.).
In general while the mechanics of the processes are quite clear on their own when they get wrapped up inside an Agent or a GenServer they become fuzzy (to me). Where is the waiting loop in them?
Thanks!
Trending in Questions
Other Trending 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
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixirconf-us
- #elixir-ls
- #ai
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 8- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
peerreynders
GenServerthe “waiting loop” is the part responsible for calling the varioushandle_callbacks, you don’t get to see the loop because it is part of the generic OTP behaviour.Agentthe “waiting loop” waits for messages to arrive. Those messages contain the functions sent to it to update it’s internal state - the state that gets to be maintained as part of the recursive loop call.So really you should be focusing on
GenServeras it is the natural progression from the recursivereceiveloop.As far as I can tell
Agentreally isn’t about the notion of a process but it’s about about state management without autonomous access control modelled on how Clojure’s Agents manage shared state where it can only be accessed via special function calls.GenServercompletely controls its internal state and the way it’s accessed through thehandle_callbacks.Agentis completely at the mercy of the functions that are sent to it from other processes.So as such
GenServerhas a far greater autonomy over it’s internal state than anAgentdoes.I really don’t think
Agentis a suitable solution here. Sounds more like X should be aGenServerwhile Yn could be Tasks (example). Tasks themselves aren’t based onGenServerbut are just some (very useful) convenience code aroundspawn,link,receive.alco
I think this is a perfect use case for
Task.Since your problem is basically processing a collection of items concurrently, you should look into using
Task.async_stream. Read carefully about themax_concurrencyoption, usually it is more beneficial to have N concurrent processes for data processing where N is the number of hardware threads in your CPU. However, to achieve maximum throughput, you’d need to test and measure. If most of the time is spent waiting for data to be fetched from a URL, having more processes may speed things up.So, assuming process
Xhas to spawn all the tasks and wait for them all to finish, it may look as follows:If, on the other hand, your process
Xhas to be able to handle messages from other processes while allYntasks are working, thenXshould be a gen server with at least the following basic functionality:I’d also recommend reading up on
Task.Supervisor. It’s useful for keeping all tasks processes rooted under a dedicated supervisor, especially when there’s a possibility that a task may crash. A task spawned usingTask.asyncwill take its calling process down if it crashes, whereas when usingTask.Supervisor.async_nolink, the calling process will not be linked to the task and will be able to receive the:DOWNmessage like i showed in my example above.zerogvt
You’re fantastic guys! Thanks a mil.
So I followed your advices (halfway) and made
Xinto a GenServer. Currently looks like this:Though I’d like to keep
Yns as GenServers too because I might opt to keep them around instead of having them performing a one-off task (imagine that each of them is kind-of monitoring its assignedurllike say implementing a hook back toX.Note: I don’t like selecting a “winner” answer and I won’t do that. Reasons: 1. this reminds me of StackOverflow and my experience there as per community quality was very bad - I don’t want to go down that road again (or any road like it) 2. Purpose here is to respectfully discuss and learn (at least for me). Since all answers help me it would be unjust to select one. Instead of all these competitive logic I’ll peruse the
heartbutton which fits better with my mindset.tty
I would suggest not keeping the process performing work around. If this is
Ynthen let them die once they are finish. Otherwise keepYnaround but spawn another process to do the work.peerreynders
Have a look at poolboy and for educational purposes pooly (though some of the process configuration code could use some updating). But personally I’m more in the short lived processes camp - it’s easier to keep something healthy for a shorter period of time.
david_ex
I’ve written a blog series rewriting
Poolywhile updating it with newer language features (e.g. Registry and DynamicSupervisor): http://davidsulc.com/blog/2018/07/09/pooltoy-a-toy-process-pool-manager-in-elixir-1-6/zerogvt
Wow, thanks!
I think I should go over Hao’s book before diving into that tho. Feels a bit too advanced right now.
So many things - so little time.
peerreynders
Give Chapter 3, 4 in this free sample (if you like it, good quality DRM-free epub/pdf for purchase from ebooks.com) a read and then dive into the hexdocs for
SupervisorandDynamicSupervisorand whatever else strikes your fancy from the MODULES - Processes & Applications sidebar.