Hacker News new | ask | show | jobs
by sb8244 1244 days ago
> just like the concurrent code of gen_server

I found this a really interesting read, but this stuck out because it doesn't jive with my mental model of gen_server.

gen_server is fully serialized. Even the code underpinning it is not concurrent.

Now I guess gen_server does expose some top level functions to simplify sending/receiving a message into the process, but the process itself is serial.

And this is part of the genius of gen_server to me. You don't need to think about your state concurrently because it processes a single message at a time. Your system executes concurrently, but the individual components do not.

Maybe that is what the post means and I misinterpreted it.

4 comments

Yup, that's my understanding too -- what Erlang does extremely well is abstract away and isolate the concurrency mechanisms, allowing you to think of the details of (these concurrent) processes, linearly.
I remember when I was learning Elixir—I asked my co-worker / Elixir mentor how Elixir solves concurrent programming, data access, etc. His cheeky but accurate response was "How do you solve a problem that you don't have?"

His point was that the paradigm is so different at the VM level, that many things become irrelevant to the conversation. That said, there still are concurrent programming challenges on the BEAM, but it's very minimal compared to languages where it's not baked in.

Ruby Ractor is a good example of how a VM-backed concurrency mechanism will likely change how programs in that language can be built.

Yeah they mention that in 2 of the 6 points arguing in favor of behaviors:

2. The application programmer writes sequential code, all concurrency is hidden away in the behaviour;

4. Easier for new team members to get started: business logic is sequential, similar structure that they might have seen before elsewhere;

Adding on to sb8244's comments; writing sequential code is very nice, but it's not the gen_server behavior that gets you that. It's the lightweight processes.

gen_server is useful, but it's not much more than receive in a tail recursive loop and conventions around messages, most specifically about if the sender expects to receive a reply or not. It's not magic, and it's written in clear Erlang that anyone with a week of Erlang fiddling can understand (which kind of is magic; almost everything in OTP is clearly readable)

Concurrency comes from running many processes each with their own message queue.

Thanks for that. My thought is probably just semantics then.

I think it's even more nuanced, but doesn't really matter for this type of post.

(I am actively writing a chapter exploring this topic, so is has been top of mind.)

gen_server is a serializer, it is the point of it to begin with. Could be called gen_serializer ;) Because we need to update the state inside of it without locks.

It is usually fine, for parallelism just use a pool of gen_servers or many gen_server processes that would map to your data model well (example, one gen_server for each network socket).

Though, these properties of gen_server come from the fact it is just a single erlang process.

> just use a pool of gen_servers or many gen_server processes

I think architecting an Erlang system can be kind of tricky because you do have to think about all these processes sort of co-existing at the same time and how they interact. With one system I was involved with, we weren't really satisfied with how we'd divided things up among different behaviors, and did some refactoring. It wasn't difficult, but it did require a different way of thinking about things. When we had it all working, I was really satisfied with the results though. That thing was robust, and quite resilient.

I miss working with Erlang. It's tricky to find people who are using it or Elixir in the sweet spot, IMO. Lots of "it looked cool and we wanted to play around with it" out there, as well as some people thinking it'll magically make their systems "internet scale".

My best experiences with it have been semi-embedded systems where it's not doing too much distributed computing, but where "robust" and "predictable" are important qualities.

> I think architecting an Erlang system can be kind of tricky because you do have to think about all these processes sort of co-existing at the same time and how they interact.

I find it easier to think about each process in isolation --- what messages does it get, and what does it do with them; if it needs to send messages, who/where does it send them to and what will it get back, including errors or timeouts and not worrying about what the other process does in the moment.

The overall behavior of a system built from communicating processes can get hard to predict though. You build up observations, intuition, and escape hatches over time.

Yes, but... Merriam-Webster also acknowledges that the use of "jive" in this sense "seems to have increased each decade since the 1940s, and may often be found in reputable and edited sources today".

https://www.merriam-webster.com/words-at-play/jive-jibe-gibe

"... it seems possible that this use of jive will increase in the future, and if it does dictionaries will likely add it to the definition."

Language evolves.