Or you could just use the Actor model, which I like much better than CSP. (Or at least I think I'll like it better when I finally understand it.)
Go hits the concurrency nail on the head
231–240 of 318 posts
Re: Go hits the concurrency nail on the head
#232Earlier quoted context omitted.
Practically every language includes stuff higher level than bare mutexes and atomics. That people use them doesn't mean other options aren't available . And yeah, totally 100% agreed, most people should never implement them themselves. But "futures", "blocking queues", "synchronized maps", and "locked objects" (e.g. a synchronized wrapper around a java object) are extremely common and often higher level than channels…
True, there are plenty of primitives available. However I found many of them are mainly for synchronizing low-level access to shared-data (e.g. the concurrent data structures, synchronized objects, mutexes), etc. Primitives for synchronizing concurrent control flow (like Go's select()) seem less common. E.g. in Java I would have some executor services, and could post all tasks to the same single threaded executor to…
Channels though are everywhere, and sample code tends to look almost exactly like introductory Go stuff[1] - Java has multiple BlockingQueues which serve the same purpose as a buffered channel, and SynchronousQueue is a non-buffered one. Though they don't generally include the concept of "close"...
But streams do have the "close" concept in nearly all cases, and streams are all over the place in many many forms, and have been for a long time. They generally replace both select and channels, but are usually much easier to use IMO (e.g. `stream.map(i -> i.string())` vs two channels + for/range/don't forget to safely close it or you leak a goroutine). Some of that is due to generics though.
[1]: https://docs.oracle.com/javase/7/docs/api/java/util/concurre...
---
some alternate stream concepts are super interesting too, e.g. .NET's new pipelines: https://blog.marcgravell.com/2018/07/pipe-dreams-part-1.html
Re: Go hits the concurrency nail on the head
#233Its fairly interesting that this article doesn't mention actors, futures/promises and async/await style co-routines which are all extremely available in all of the major languages available today and broadly used (with the possible exception of golang). Frankly, I think the concurrency story is one of the weaknesses of golang. Contrary to what this article says you cannot stop thinking about concurrency in your code…
All of those interfaces are trivial to implement in Go precisely because Go implements a much stronger abstraction. By contrast, if you only have those other abstractions you're quite limited in how you can structure your code. (You might not realize how limited you are, however, if those are your only options.) As the article says, most languages settle for those interfaces because they can mostly be implemented as…
Conversely most other modern, mainstream languages can mimic golang concurrency as a library.
Re: Go hits the concurrency nail on the head
#234Its fairly interesting that this article doesn't mention actors, futures/promises and async/await style co-routines which are all extremely available in all of the major languages available today and broadly used (with the possible exception of golang). Frankly, I think the concurrency story is one of the weaknesses of golang. Contrary to what this article says you cannot stop thinking about concurrency in your code…
> actors, futures/promises and async/await style co-routines which are all extremely available in all of the major languages Language features are indeed available. Runtime features backing them are only available in Go, erlang and .NET. If you only need concurrency for CPU bound calculations, even C++ has decent options, e.g. OpenMP works great for my tasks. However, OpenMP offers nothing for IO. The point of go’s c…
Re: Go hits the concurrency nail on the head
#235Go concurrency is just threads. It's a particularly idiosyncratic userland implementation of them. There are two claims here I'd like to unpack further: 1. "I've measured goroutine switching time to be ~170 ns on my machine, 10x faster than thread switching time." This is because of the lack of switchto support in the Linux kernel, not because of any fundamental difference between threads and goroutines. A Google eng…
That Go concurrency is threads is the point of the article. It says this explicitly: "You can think of goroutines as threads, it's a fairly good mental model. They are truly cheap threads". If OS threads become as cheap as userland threads then the implementation of userland threads becomes unnecessary, but the conceptual model stays the same. In other languages, asynchronous APIs return futures or have explicit call…
Re: Go hits the concurrency nail on the head
#236Its fairly interesting that this article doesn't mention actors, futures/promises and async/await style co-routines which are all extremely available in all of the major languages available today and broadly used (with the possible exception of golang). Frankly, I think the concurrency story is one of the weaknesses of golang. Contrary to what this article says you cannot stop thinking about concurrency in your code…
Describing its concurrency model as one of its weakness is a bold statement, because it's probably one of the biggest reason it became widely adopted. Everyone is different, but Go 's concurrency model has been the easiest for me to reason about. And I've dealt with my fair share of "async/await".
At high concurrency levels almost everything abandons standard golang concurrency patterns and tools.
Re: Go hits the concurrency nail on the head
#237Earlier quoted context omitted.
Ericsson abandoned Erlang, or Erlang abandoned Ericsson, depending on how you look: Ericsson banned it internally, and shortly afterwards when the Erlang team managed to get it open sourced, they resigned from Ericsson and founded their own Erlang company. (source: http://webcem01.cem.itesm.mx:8005/erlang/cd/downloads/hopl_e... )
So does Ericsson still use Erlang in their recent network hardware etc?
Ericsson has a small team maintaining erlang and they are the steward of Erlang.
Re: Go hits the concurrency nail on the head
#238> Programming with threads is hard - it's hard to synchronize access to data structures without causing deadlocks; it's hard to reason about multiple threads accessing the same data, it's hard to choose the right locking granularity, etc. It's almost as if we need a language that has a focus on data races, concurrency and fearless threading.
Hah! Good one. To anyone else not in on the joke, parent is referring to the language that is often discussed on HN and known for having a sometimes overly enthusiastic community, Pony: https://www.ponylang.io/
https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/198700...
The discussion of pitfalls surrounding Ada's task facility is eerily familiar to what you're reading in this thread 31 years later.
Re: Go hits the concurrency nail on the head
#239According to the author Go make concurrent programming "the best experience, by far, compared to other popular programming languages today." I beg to differ. I fail to see why I should choose Go over Elixir/Erlang for concurrency. Elixir's cuncurrency mechanisms are at least as good — and I would argue better — than Go's, and Elixir as a language has an expressiveness that Go lacks.
How are the deployment, library ecosystem, build, and tooling stories for Elixir? Note I don't really care about the answer to the above, I just wish as a profession we could get past the tribalism and boosterism and have rational technical dicussions about things that matter as opposed to banal declarations about 'expressiveness' etc.
Build: same, come fully ready out of the box.
Library: there is everything and you can use any erlang library for free. 35 years of production experience.
Tooling: see above. Everything to debug and instrument on the fly. Dynamic tracing for everything for free. Logger. Etc etc. Fully interoperable runtime dynamically for free. Advantage of using a runtime that has spent 35 years optimising for reliability in production.
So yeah. We could but then people would not understand. Erlang/Elixir have a decade of advance over Go for that kind of tooling and production-readiness
Re: Go hits the concurrency nail on the head
#240Earlier quoted context omitted.
All of those interfaces are trivial to implement in Go precisely because Go implements a much stronger abstraction. By contrast, if you only have those other abstractions you're quite limited in how you can structure your code. (You might not realize how limited you are, however, if those are your only options.) As the article says, most languages settle for those interfaces because they can mostly be implemented as…
> By contrast, if you only have those other abstractions you're quite limited in how you can structure your code. OK... but what languages only have those abstractions?
What I really meant to get at was that Go provides a flavor of threading that is lightweight, simple, and ergonomic. The threading construct is a first-class citizen and fundamental to both the language design and its implementation tradeoffs. Threading, lexical closures, and GC were designed and implemented holistically. Go takes a performance hit for its seamless support of closures (lots of incidental heap allocation), for example, but they did it because notwithstanding the Go authors' utilitarian goal it was important that the core abstractions remained relatively unadulterated and natural. If this wasn't the case (if it was just about avoiding manual memory management), Go could have required explicit capturing of lexicals, like C++ and Python do. People complain that Go doesn't have a lot of sophisticated features, but that's because everybody is focused on typing and generics. But modeling execution flow is at least as interesting academically and important commercially. While Go seems simple, supporting these constructs the way Go does is actually really difficult. Which is why it's so rare to find.
I intentionally didn't mention channels because while syntactically nice the real internal complexity (and payoff) comes from the closures. Channels are something of an implementation detail which you can easily hide inside closures in a functional-style of programming; threading + closures allow you to implement coroutine semantics very cleanly (i.e. no async/await necessary) and, if you so desire, transparently. (And it just occurred to me that async/await is such a misnomer. In a coroutine caller and callee are logically synchronous. The fact that languages like Python, C#, and C++ use async/await terminology shows how they put the cart before the horse--these constructs were designed and implemented for the very specific use case of writing highly concurrent async-I/O services, and they stopped at making that use case moderately convenient. They're a very leaky abstraction. See function color problem mentioned in the article.)