Hacker News new | ask | show | jobs
by wongarsu 1244 days ago
> For example, you can't recreate this in Go or Rust

If you're willing to make your "lightweight processes" OS threads you could kind of make it work. E.g. Rust gives you both panic hooks (to notify everyone else that you died) and catch_unwind to contain the effect of a panic (which generally stops at a thread boundary anyways). But of course that only scales to a couple hundred or thousand threads, so you probably have to sacrifice a lot of granularity.

And any library that links to C/C++ code has the potential to bring the whole process down (unless you make your "lightweight processes" just "OS processes", but that just makes the scaling problems worse)

2 comments

Lightweight processes is explicitly not os threads in at least two senses: smaller footprint in memory, and no system call for every context switch.

It’s explained in many documents about lightweight processes, of course for elixir/erlang/beam but also for Go and Crystal and even going back to Solaris Internals and modern Project Loom for upcoming JVM situations

Erlang's beam processes are undoubtedly awesome. But if we start with the premise of "achieving the same goals without Erlang" I think it's entirely valid to start with "what does our process primitive look like". With just 16GB of RAM my laptop is quite memory constrained, but according to task manager I'm still running 5200 threads accross 350 processes right now. Many use cases that required light threads/processes 37 years ago or even 20 years ago would work with OS threads by now. Of course many others don't, which is where the Erlang popularity comes from.
It takes on the order of nanoseconds to start an Erlang process. They are also extremely lightweight memory-wise. And Erlang VM tries to keep context switching between CPU cores to a minumum. And all processes get more-or-less equal share, so it's hard to get a process consuming all of CPU and never yielding back to other processes.

So firing off and monitoring processes becomes second nature easily. Rarely so in other languages

OS threads would defeat the purpose though. You can run millions of BEAM processes. Threads are a lot more expensive and still run the risk of taking over your system with an infinite loop.
OS threads are actually premptive, so an infinite loop is really less of a deal than one in Erlang. Erlang is really not premptive, it's just that function calls are automatically (potential) yield points, and you can't loop without function calls because of the construction of the language; if somehow you did manage to get a real loop into a process, that scheduler would be stuck forever, and you'd end up with a broken BEAM when you triggered something that requires coordination between schedulers --- I forget what sorts of things do that, but code purging can't finish without each scheduler doing housekeeping, etc.

Meanwhile, your OS thread will just keep eating CPU, but everything else is fine.

You're right about the number of threads though. It takes a lot more memory to run an OS thread than a BEAM process, and I'm not sure OS schedulers will manage that many threads even if the memory is there (but I could be wrong... getting things to work nicely at 50k threads may be sufficient for millions)

Unless code is exiting the BEAM itself, an infinite loop that bypasses yield points shouldn't be possible.

Doing this at such a granular level is also one of the reasons that you can run a database that thousands of processes are accessing, within the same runtime, without a performance impact to the overall system.