Most active commenters
  • mordocai(3)
  • sagichmal(3)
  • zeeboo(3)

←back to thread

Go channels are bad

(www.jtolds.com)
298 points jtolds | 11 comments | | HN request time: 0.001s | source | bottom
Show context
sagichmal ◴[] No.11211112[source]
This is a frustrating and overly-exasperated post which reaches conclusions that have always been part of the Go canon. APIs should be designed synchronously, and the callers should orchestrate concurrency if they choose -- yes! Channels are useful in some circumstances, but if you just want to synchronize access to shared memory (like the author's example) then you should just use a mutex -- yes! These are well understood truths.

Novices to the language have a tendency to overuse channels. Here is Andrew Gerrand addressing precisely this point two years ago at GopherCon: https://www.youtube.com/watch?v=u-kkf76TDHE&t=815

Neither the referenced performance characteristics via Tyler Treat, nor the FUD surrounding channel-based program architecture, invalidate channels generally. One does have to think carefully about ownership hierarchies: only one goroutine gets to close the channel. And if it's in a hot loop, a channel will always perform worse than a mutex: channels use mutexes internally. But plenty of problems are solved very elegantly with channel-based CSP-style message passing.

It's unfortunate that articles like this are written and gain traction. The explicit instruction to [new] Go programmers is that they should avoid channels, even that they are badly implemented, and both of those things are false.

replies(7): >>11211239 #>>11211262 #>>11211272 #>>11211656 #>>11211660 #>>11214091 #>>11228064 #
1. mordocai ◴[] No.11211239[source]
As a non-go programmer, I'm pretty sure the author made some very good objective arguments that channels are in fact badly implemented.
replies(2): >>11211298 #>>11211519 #
2. sagichmal ◴[] No.11211298[source]
Read Tyler's original article for a less FUDdy take on it. Channels are always slower than mutexes, which is obvious when you understand their implementation. They are definitely not badly implemented as a general rule.
replies(1): >>11212165 #
3. voidlogic ◴[] No.11211519[source]
Hammers make poor screw drivers. Mutexes, atomic integer operations, and channels (buffered and unbuffered) all have their place. You will think any of these is "badly implemented" if you choose the wrong tool for the job.
4. zeeboo ◴[] No.11212165[source]
The api definitely is badly implemented and makes them hard to use. That's the point of the post. There are design decisions around channels (sends panicing, close panicing, nil channels blocking) that make them hard to understand, follow, and compose concurrent solutions.
replies(1): >>11212804 #
5. sagichmal ◴[] No.11212804{3}[source]
I'm sorry, but I don't agree with any of your assertions. The constraints on channels are there not as an accident of a bad implementation, but as deliberate decisions to enforce a certain set of design contracts. Panics on invalid channel operations enforce those contracts. That nil channels block is actually an incredibly handy feature: see e.g. https://github.com/streadway/handy/blob/b8cb168/breaker/brea...

Without exception, hitting one of these corner cases exposes an error in design, from Go's perspective on CSP. You can disagree with that perspective on a subjective basis ("hard to understand") -- but you can't lift that opinion to objective fact, and you certainly can't claim these artifacts of design as evidence of incompetence or neglect.

replies(2): >>11213487 #>>11213762 #
6. mordocai ◴[] No.11213487{4}[source]
While I agree all of this is subjective, I would argue that something being composed of "deliberate decisions to enforce a certain set of design contracts" doesn't mean those decisions nor the design contracts are good. Nor does it automagically make a good implementation.

In addition, making bad design decisions that you think are good is actually one of the best types of evidence for incompetence (though not neglect, in this case).

I don't personally have enough data to have a strong opinion on where Go channels falls here, but I don't think any of your arguments here have any bearing on the idea that Go's channel implementation is bad.

replies(1): >>11213567 #
7. AnimalMuppet ◴[] No.11213567{5}[source]
But using something in the way it was not intended to be used, and then complaining that it works badly, is evidence of incompetence on the part of the user, not the designer.

> I don't personally have enough data to have a strong opinion on where Go channels falls here, but I don't think any of your arguments here have any bearing on the idea that Go's channel implementation is bad.

If sagichmal is correct, zeeboo is trying to use channels in a way that they were explicitly not designed to be used. That makes zeeboo's criticism very likely to be invalid. (It is the one who uses them as they were designed to be used who knows what the actual problems with the design are.)

replies(2): >>11213634 #>>11213771 #
8. mordocai ◴[] No.11213634{6}[source]
That's where the purely subjective argument comes in I suppose.

The argument could be made that go's channels SHOULD be able to handle zeeboo's use case and the fact that they weren't designed to be able to handle it makes them bad.

replies(1): >>11213875 #
9. zeeboo ◴[] No.11213762{4}[source]
It's great that panics happen when you violate those contracts. That is a deliberate design decision and I agree with it. However, the contracts that they enforce cause real problems evidenced by the article. Small additions might make those contracts more general and make channels more applicable. In my opinion, you should be able to attempt to send on a channel that could be closed in the same way that you are allowed to check if an interface contains a specific concrete type without panicing. In my experience, this would allow for a number of useful patterns that are very hard to express right now.

Nil channels blocking is definitely a deliberate design decision and has valid use cases. I use them frequently when I have a channel based design. It also isn't the thing that most people first expect since they have the opposite analog for using anything else that is nil: panics. The article which I assume you read makes only this point.

I never attempted to lift statements that are obviously opinion based (anything that has a judgement of something good or bad) as objective fact.

Here's a proposal I worked on with a coworker to make channels better that might give you more of an idea of why I'm suggesting that the current design has flaws: https://github.com/golang/go/issues/14601

Given how much weight channels are in the language specification and memory model, it would be nice if they were more generally applicable and easier to use for more concurrency situations.

10. zeeboo ◴[] No.11213771{6}[source]
My criticism is that the design limits the places where they are valid. I'm not trying to use a hammer where a screwdriver is required, I'm saying that if the hammer was designed differently, we'd be able to use it in more situations appropriately.

It's as if someone created a gun that fired backwards and I said "hey, it might be better if the gun fired forwards. we'd be able to use it in more situations." and people responded with "you shouldn't use a gun that fires backwards if you want to fire forwards." I totally agree, but it's missing the point.

11. AnimalMuppet ◴[] No.11213875{7}[source]
Only if go doesn't have a good way of handling that use case (even if it is something completely different from channels). I don't know enough to know whether it does.