Hacker News new | ask | show | jobs
by ksbrooksjr 1241 days ago
I'm not a Go expert but preemptive scheduling of goroutines is supposed to be one of the primary benefits of Go as a language [1]. Although I'm not sure if there's any runtime that adopts preemptive scheduling as fervently as the BEAM. Even the regular expression engine is preemptive in Erlang, which prevents regular expression denial of service attacks [2].

[1] https://go.dev/src/runtime/preempt.go

[2] https://www.erlang.org/doc/man/re.html#:~:text=run/3%20alway....

2 comments

Regex DoSes can be made impossible without using any concurrency. See Go's and Rust's implementation. Also see https://swtch.com/~rsc/regexp/
I wasn't trying to imply that concurrency is the only way to mitigate ReDos attacks, I was just pointing out that the BEAM applies preemption seemingly everywhere, which I found interesting.
The BEAM misbehaves when a scheduler gets stuck in a process (or other activity) for too long. As a result, anything that can take a long time needs to have yield points. This is a human process; when I started using Erlang, garbage collection didn't yield, List1 ++ List2 took forever with large lists and didn't yield, we didn't have line numbers in backtraces, and we had to hotload our code uphill in the snow both ways. It's not unusual for a new OTP release to have added new yield points in BIFs or NIFs that could run long or even in core VM workings.
There was someone recently on HN who didn't know about the possibility of non-backtracking implementations of regex.
It wasn't non-cooperative pre-emptive scheduling for a while, which is why I kept pushing Elixir, until Go implemented it. Now Go has the same benefit as Elixir, but it's very, very fast.
Yeah with preemptive scheduling, static typing, and better cpu utilization Go is a pretty compelling option for Erlang and Elixir users.
It's not immutable, there is no messaging, no hot-swap, no supervisors, it's not FP, and it doesn't have transparent support for clustering.

Also, it's not memory-safe, 30ys old, and battle-tested pretty much everywhere.

There are definitely trade offs when switching from Elixir or Erlang to Go. If you're a functional programmer who can't live without immutability, or you plan on running a cluster of machines that can communicate with each other and hot-swap code into the running system, then Elixir and Erlang are good choices.

If you have some extremely CPU intensive code, or you like cross compiling to a lightweight binary, or you need static typing (without giving up preemptive scheduling), Go is a decent choice.

Elixir and Erlang are not slow by any metric, but there are faster languages. Discord famously had to augment their Elixir code with Rust for example to scale to 11 million users [1].

[1] https://discord.com/blog/using-rust-to-scale-elixir-for-11-m...

that is much better point, but erlang gives you reliable system by default and you have to try really hard to make it crash, whereas go is just regular compiled language and such programs typically crash more easily/often.
Erlang is definitely more fault tolerant than most languages, but I've found that static typing tends to catch a lot of errors in development that would otherwise crash an application in production. The compiler won't catch every bug, and you'll still typically have to restart a crashed service periodically (via systemd, or a container orchestrator, or whatever process manager you use), but it definitely helps.

Gleam is a pretty good choice if you need type safety and you want to run on the BEAM https://gleam.run/. It still has the same performance characteristics as Erlang (which it compiles to), but at least it gives you type safety.