3 ms·
Channels have some other annoyances that make them less useful than they seem at first glance. One is the ownership model. You can close a channel, and sends w
by lobster_johnson 10y ago
Channels have some other annoyances that make them less useful than they seem at first glance.
One is the ownership model. You can close a channel, and sends will then panic (there's no way to check if a channel is open), so ownership is always in the hands of the code that writes to the channel. You can -- and must, if you ever want multiple producers with a single channel -- abstract ownership into a wrapper that keeps the channel and a tracks whether the channel has been closed, but it's tedious to implement it over and over (it needs to be thread safe, too).
It's tempting to use channels as part of a public interface (between two cleanly separated packages), but this nearly always is a bad idea. Channels just don't compose well as an iteration construct, and you encounter ugly surprises such as realizing the caller is using an unbuffered channel causing stuff to block. It's almost always better to offer a callback interface (push) or an iterator interface (pull), and then either side can use channels internally, or not at all, as needed.
In practice, it's sometimes surprisingly hard to avoid goroutine leakage with channels. It's a simple mechanism that gets complicated fast, especially as you combine them with mutexes and error handling (though ErrorGroup is a timesaver that ought to be part of the standard library).
And finally, the behaviour of nil channels (they block forever!) is unfortunate. It is touted as a feature, but for me it has been exclusively the source of surprising bugs.
- integrii 10y agoYou can check if a channel is closed or not. You can even use it gracefully as an iterator.
- nothrabannosir 10y agoBoth you and parent are right. To be exact: you cannot "non-destructively" check if a channel is closed. I.e.: the way to check is by using a select statement to do a "soft write", I.e. "try to send this value but don't panic if it fails." Same for reading. This means you can't check the state of a channel without modifying it if it isn't closed.
- frou_dh 10y agoThat reminds me of Unix FDs and the distinction between whether your user has permission to write a file, and whether an open file is actually open-for-writing. I was thankful to find out about fcntl(2) + F_GETFL, and get out of a 'dummy write' train of thought.
- dom0 10y agoFun-fact: In the POSIX model you cannot write into a private mapping created through a FD with the writable bit not set. (Or, more precisely, Linux won't let you set the write bit of the mapping). Even though that would be a rather useful thing to have, and wouldn't be hindered by hardware or kernel (which already does CoW of pages).
- gpderetta 10y agoI know nothing about go, but assuming the reading end of the channel is running concurrently, the only way to meaningfully check for closeness is actually trying, any other check would be meaningless as an open channel could have been closed immediately after the check would have returned 'closed'.
- Animats 10y agoSending to a closed channel is fatal, as is closing it. There's no way for multiple senders sending to a channel to tell if somebody closed it without risk of crashing. Graceful shutdown of systems with lots of asynchronous communication is hard, but this makes it harder than it has to be.