6 ms·
For me, the goroutines + channels + select is what makes Go leagues above any other popular language. As far as I know, no other popular language allows you to
by paskozdilar 4y ago
For me, the goroutines + channels + select is what makes Go leagues above any other popular language.
As far as I know, no other popular language allows you to read from multiple queues at the same time, which is an extremely useful pattern in concurrent programming. The only way to "select" from multiple sources in other languages is to use some kind of poll/select syscall on file descriptors - and even that is very limited, since kernel (at least Linux) does not allow userspace programs to create private file descriptors for intra-process communication - they must always be bound to some file/pipe/socket.
- fasterthanlime 4y ago> As far as I know, no other popular language allows you to read from multiple queues at the same time Off the top of my head, that's certainly possible in Rust, C++ and Java - probably many others I just don't know about. That particular bit of concurrency goodness comes from the 70s, so you can be sure other languages picked it up.
- npe 4y agoAs I understand it, he's talking about select/alt (i.e. guarded commands from CSP) being a native feature of the language rather than callback-based approaches. It's possible to implement CSP channels in most languages, but they're not first-class like go.
- samhw 4y ago> It's possible to implement CSP channels in most languages, but they're not first-class like go. But does that matter? In all my experience, I can't think of any instances where that wouldn't be a distinction without a difference. (Perhaps I'm missing something, though.)
- fasterthanlime 4y agoDefaults matter because friction matters, but friction there is largely removed by having a decent package manager, so I personally don't think it matters (though the topic of "what batteries should be included" has far from run its course).
- npe 4y agoThe minute you put language constructs in the base syntax and runtime of the language, it's a lot more than friction. Love it or hate it, Go is inextricably tied to CSP.
- npe 4y agoIt matters a lot IMO. Most systems programming languages can implement whatever concurrency primitives you care to use, but most people default to whatever is provided by the OS/language because concurrency is hard. Having first-class syntactic sugar over a concurrent runtime bakes in a certain programming style in the language, which strongly determines how the language is used and the programming style. Go comes out of the Newsqueak/Aleph/Limbo family which has a very different style of programming compared to a lot of other languages.
- samhw 4y agoI think there's a difference between 'in the standard library' and 'in the language', though. They seem to be praising Go for doing the latter. And the technical language in which it was expressed gave me to think there was some technical motivation for that, as opposed to sociological - but if what they meant is what you said, then I certainly wouldn't disagree with that.
- npe 4y agoI'd argue that Go is explicitly sociological. Most of the novel ideas in Go (process calculi/guarded commands in a concurrent language) were originally embedded in Cardelli and Pike's Squeak back in the 80s. The rest is trying to standardize the way scalable web applications are built.
- Mawr 4y agoIt's the opposite - pointing out that X can just as well be implemented in language Y is the irrelevant point because anything can be implemented in any turing complete language. Where languages differ is what they make easy to use, or first class. As an example consider Go's autoformatter gofmt. It got released with the language, pushed and marketed as the way to format your code - first class. As a result, virtually all Go code is uniformly formatted. Contrast that with autoformatters in other languages pre-Go. They existed, but often multiple per language, each with hundreds of configuration options, all with minimal uptake in their ecosystems.
- thestoicattack 4y agoAda too, I think.
- pyjarrett 4y agoAda has had this built-in for decades, and even allows selecting from one of multiple waiting queues (entries) using a `select` keyword.
- bheadmaster 4y agoIf you could spare some time, would you please demonstrate an example? Any language of those mentioned would be OK.
- fasterthanlime 4y agoHere's a Rust example, with tokio: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=825256f548eb9bb5df528704867f80fd https://play.rust-lang.org/?version=stable&mode=debug&editio... - I don't have time to come up with Java/C++ examples, but I'm sure others will. (If your point was about it being _built into the language_, then it definitely stands, see the other discussion in the parent comment thread)
- paskozdilar 4y agoYeah, I guess I overestimated the complexity of such mechanisms. I mean, still, you need some kind of runtime for the asynchronicity, but the Rust version seems fairly OK (apart from the function coloring, but that's another story). I guess I just like it being built into the language. Plus no function coloring (everything is asynchronous, but appears synchronous) really makes it easy to build complex systems.
- autarch 4y agoHere's a rust example - https://github.com/autarch/channel-select https://github.com/autarch/channel-select
- moralestapia 4y ago>read from multiple queues at the same time That's a trivial thing in javascript.
- metadat 4y agoHow? Javascript is single threaded run loop.
- lalaithion 4y agoConcurrency is not parallelism: https://go.dev/blog/waza-talk#:~:text=In%20programming%2C%20concurrency%20is%20the,lots%20of%20things%20at%20once https://go.dev/blog/waza-talk#:~:text=In%20programming%2C%20....
- metadat 4y ago>read from multiple queues at the same time Agreed, and things happening "at the same time" are possible only with parallelism. Hence my question =)
- moralestapia 4y agoI interpreted "at the same time" as "without blocking", But sure you could also add parallelism using a few built-in Node modules (there's cluster and worker threads, also don't know if atomics are already in Node, they are in V8), It's not trivial anymore but also not that hard. A newcomer could figure it out in ~30 mins from the docs.
- metadat 4y agoGotcha, sounds like we interpreted it differently. I appreciate you taking the time to clarify, I am an old hand as JS but didn't know true parallelism had become feasible these days. Thank you, sincerely!
- 4y ago
- jcelerier 4y agohere's some documentation on how to do it in C++ with boost in 2008, before go even existed: in this example two threads pull events from a single queue. https://www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/tutorial/tuttimer5/src.html https://www.boost.org/doc/libs/1_35_0/doc/html/boost_asio/tu... (of course it was possible before)
- paskozdilar 4y agoI'm not really experienced with Boost so I'm having a hard time understanding what that snippet does. Is there any example that is completely self-contained (or at least limited to STL)?
- jcelerier 4y agoBoost's io_service (since then renamed as io_context) is an implementation of a thread-safe event queue. Threads can put events in the queue (timer events, asynchronous read and write requests for networking, but one can also just push a generic lambda). This example sets up two timers which will regularly push events in the queue, while two threads processes these events. It's from before c++ had lambdas - nowadays it can be written much more tersely. I'll try to write a short example after when I'm not on my phone - it should be reduceable to 5-6 lines of setup at most
- jcelerier 4y ago=> very dumb example of processing messages from ten threads #include <boost/asio.hpp> #include <atomic> #include <iostream> #include <thread> int main() { boost::asio::io_context io; using work_guard_type = boost::asio::executor_work_guard<boost::asio::io_context::executor_type>; work_guard_type work_guard(io.get_executor()); std::vector<std::jthread> t; for(int i = 0; i < 10; i++) t.emplace_back(std::jthread([&io] { io.run(); })); std::atomic_int counter{}; while(counter < 100) io.post([&] { std::cerr << std::this_thread::get_id() << '\n'; counter++; }); io.stop(); return 0; }
- lalaithion 4y agoIf that's all you want, Haskell has had goroutines (forkIO, yes it's called "fork" but it doesn't spawn an OS level process, that's forkOS), channels, and select since 1996. https://www.microsoft.com/en-us/research/wp-content/uploads/1996/01/concurrent-haskell.pdf https://www.microsoft.com/en-us/research/wp-content/uploads/...
- otterley 4y agoPeople also want a programming language they can easily read and that has enough market share to work well in team environments.
- newaccount2021 4y ago
- aidaman 4y agonobody should ever write haskell
- jayd16 4y agoLots of languages have similar async, channel and pattern matching syntax these days. Kotlin, C#, off the top of my head. Probably a lot more.