← Back to context

Comment by mhink

1 day ago

Not to dispute too strongly (since I haven't used this functionality myself), but Node.js does have support for true multithreading since v12: https://nodejs.org/dist/latest/docs/api/worker_threads.html. I'm not sure what you mean by "M:1 threaded" but I'm legitimately curious to understand more here, if you're willing to give more details.

There are also runtimes like e.g. Hermes (used primarily by React Native), there's support for separating operations between the graphics thread and other threads.

All that being said, I won't dispute OP's point about "handling concurrency [...] within the language"- multithreading and concurrency are baked into the Golang language in a more fundamental way than Javascript. But it's certainly worth pointing out that at least several of the major runtimes are capable of multithreading, out of the box.

Yeah those are workers which require manual admin of memory shared / passed memory:

> Within a worker thread, worker.getEnvironmentData() returns a clone of data passed to the spawning thread's worker.setEnvironmentData(). Every new Worker receives its own copy of the environment data automatically.

M:1 threaded means that the user space threads are mapped onto a single kernel thread. Go is M:N threaded: goroutines can be arbitrarily scheduled across various underlying OS threads. Its primitives (goroutines and channels) make both concurrency and parallelism notably simpler than most languages.

> But it's certainly worth pointing out that at least several of the major runtimes are capable of multithreading, out of the box.

I’d personally disagree in this context. Almost every language has pthread-style cro-magnon concurrency primitives. The context for this thread is precisely how go differs from regular threading interfaces. Quoting gp:

> The go language and its runtime is the only system I know that is able to handle concurrency with multicore cpus seamlessly within the language, using the CSP-like (goroutine/channel) formalism which is easy to reason with.

Yes other languages have threading, but in go both concurrency and parallelism are easier than most.

(But not erlang :) )

Even the node author came out and said the concurrency design there was wrong and switched to golang. Libuv is cool and all, but doesn't handle everything and you still have a bottleneck, poor isolation, and the single threaded event loop to deal with. Back pressure in node becomes a real thing and the whole thing becomes very painful and obvious at scale.

Granted, many people don't ever need to handle that kind of throughput. It depends on the app and the load put on to it. So many people don't realize. Which is fine! If it works it works. But if you do fall into the need of concurrency, yea, you probably don't want to be using node - even the newer versions. You certainly could do worse than golang. It's good we have some choices out there.

The other thing I always say is the choice in languages and technology is not for one person. It's for the software and team at hand. I often choose languages, frameworks, and tools specifically because of the team that's charged with building and maintaining. If you can make them successful because a language gives them type safety or memory safety that rust offers or a good tool chain, whatever it is that the team needs - that's really good. In fact, it could well be the difference between a successful business and an unsuccessful one. No one really cares how magical the software is if the company goes under and no one uses the software.