denna
In a project I had a genserver that holds its local state. This state isnt exceptionally big but part of it was a list of 1000 ids that is a few times per second updated( items removed or added). The effect of this was that every few seconds the process appeared stuck ( i guess something related to garbage collection ). This problem got resolved by putting the list into a separate process.
Now I wonder what could be a general rule for processes. When should i separate a part of a state into a separate state?
If I add a item to the beginning of a list inside a map does this imply the complete map is copied?
Trending in Questions
Hey guys,
I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly
Do you guys have any suggestions what is the best prac...
New
Hello!
Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app.
I creat...
New
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
Anyone here using Honeybadger?
My Honeybadger account is being overwhelmed with noise from some bots. Seeing a lot of
Bandit.HTTPError...
New
So my question is quite simple and i have found no conclusive answer on forum, google or AI.
Should we use :erlang.float for Integer to ...
New
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New
Other Trending Topics
A new Erlang announcement has been posted:
Original announcement:
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve.
They are GUI (Emerge) and State management (S...
New
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
- #javascript
- #podcasts
- #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 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
hauleth
Maybe you should have used ETS table instead of list? If there are random updates it can make it slower even further.
lud
If the order of IDs in you list doesn’t matter, you can keep the list sorted to get better performance when inserting or removing IDs.
Or using a
MapSetcould be better too. But in any case 1000 ids “a few times per second” is small and you should not notice a GC pause for that.benwilson512
As @hauleth notes,
:etsmay be the right call here. It has the further perk of not creating garbage collector pressure, since its items are stored in its own managed memory space instead of within the process memory.derek-zhou
When it get slow. However, as other has noted, what you are doing should not be slow; and even if it does get slow, there is other ways to make it faster, such as ets.
denna
I am sure I am have a GC pause for something related to this list. 1) Because I could tweek it a little bit by changing the GC parameters of the GenServer. 2) Because the separation of the list into another process made everything smooth.
But you are right its not the list itself. to be a bit more precise its a list of unordered integers that provide available unique ids (within a specified range).
Am I right that a list updated with [head|tail] triggers little memory movement (sorry i don’t know the right term)?
Does updating a list within a map create significantly more “memory movement”, so that the GC has to work?
For example does a change in a implies that b has to be copied?
lucaong
No, the value associated to
bshould not be copied if you changea. Rather, a new map that references the samebshould be created. The details probably depend on the size of the map (I guess bigger maps are implemented as HAMT, smaller ones possibly not), but in any casebshould not be copied if something else in the map changes: the implementation will generally try to reference as much as possible of the old immutable data structure.I suspect there is something more to your case, could you maybe share some code?
lud
I ran a quick benchmark based on a list of 1000 ids. When adding 500 existing ids and 500 new ids, then removing 500 existing and 500 not existing, ETS was the fastest.
Adding and removing 200 IDs, MapSet was faster (still on a 1000 IDs list at start).
My quick and dirty unique list implementation was the slowest in any case.
But ETS comes with its own new problems because it is like a mutable array. Now, that should not be a problem since you use another process currently, so you already have a “kind of mutable” state. But if you need to do a lot of things locally with those IDs, don’t use ETS if it is impractical I guess.
But I agree, show us some code!
krasenyp
ETS is a nice solution to your problem. One consideration, most guides show an ETS table “managed” by a GenServer but this is suboptimal. ETS allows concurrent access and a GenServer in front of it limits the concurrency. Just create a table, maybe in your Application, and access it through it’s name from a module containing only functions.
benwilson512
I think you’re confusing the practice of having a specific process that owns the
:etstable with the practice of serializing access to that table through the genserver. The two are orthogonal. You can setup a named table with read / write concurrency that is accessed directly, but still is owned by a supervised process. It is generally a best practice to put:etstables under such managed processes because it allows them to be started / stopped / restarted effectively within your application’s supervision tree.bjunc
It should probably be said that an entire book chapter could be dedicated to these situations (I believe there are a few in existence!). I’d maybe go as far as to say it’s one of the main quirks with immutable data, since you can find yourself copying the data over and over instead of what is a simple pointer update in mutable languages.
Also, a thousand IDs should not cause what you are describing; which makes me think you are replicating the data. If the ETS option doesn’t solve your problem, I’ve picked up a few tricks when dealing with this type of scenario; which might be applicable for you:
you can inspect the process’ memory usage using Observer. Runaway increases in memory may be a sign that old data is not being cleaned up as you update the ID list.
if you’re processing the IDs each in a dedicated process, you can “monitor” the process, listen for the
:DOWNmessage, and then force garbage collection (:erlang.garbage_collect()). Not ideal, but it can work. You can target particular processes as well (eg. parent process).state (memory) can come along for the ride when using Task.Supervisor with anonymous functions. Here’s a nice explanation (not a bug). Short answer, MFA is preferred. If you’re doing any supervised processing in a loop, you may be inadvertently passing a lot of data around (locking it up).