3 ms·
I certainly considered using channels here as they would make handling the potential threading issues very easy, but ultimately channels were a bad fit for read
by jrabone 14y ago
I certainly considered using channels here as they would make handling the potential threading issues very easy, but ultimately channels were a bad fit for reads (though writes would have worked well)
Could you elaborate on this? I'm just starting to play with Go and I think my first thought would be "channels". What doesn't fit here? Is just the requirement that all downstream callers would need to use channels too?
- georgemcbay 14y agoI'm okay with exposing channels as part of an API. The problem was that in my experience doing async reads (especially where the data size is variable, not fixed) where you may have multiple possible callers reading from what is basically the same resource doesn't mesh too well with channels. Say you have 3 goroutines, any of which might be requesting data from any/all of 3 connected I2C devices all on the same I2C bus. They could signal a read over a channel and then have a return channel they look for the result on, but if there is a single channel per I2C bus, how do they know the result they see is the one they asked for? (As opposed to one being asked for by another goroutine also reading from that channel). You can do it with some sort of token/id system but it gets complicated because if you read the data off the read channel and it isn't yours you have to stuff it back on there for others to read and make sure your goroutine isn't deadlocking everyone else out. This is, of course, possible to work around while still using channels in many different ways. One way is every time a client calls Read a new channel is created to return the results, but given that the data returned is of variable size and the underlying I2C layer requires you to pass in a pointer to the data buffer being used channels don't buy you much here. Plus you end up with a lot more garbage to collect in the form of new channels being created each time Read is called, which is no big deal on a "big" computer, but when doing Go programming for smaller devices I do try to minimize the amount of garbage that needs to be collected. When I first got into Go I wanted to do everything with channels and goroutines because where they fit they are awesome, but I've found the "essence" of Go is simplicity, not specific features, and sometimes a plain old mutex is just simpler than a more complex channel system. And you can, of course, pretty trivially add channels on top of the I2C API like I do in the accel_dump example, where your code knows exactly what the access patterns of any single device will be (whereas the base I2C code doesn't really know or care).
- jrabone 14y agoThanks, that's helpful. I've toying with porting some code I wrote (in Java) to access an embedded GSM modem over the serial port to Go as a learning exercise, hence thinking about the "right" way to handle the underlying read/write semantics. What you say is exactly the class of problems I've previously encountered when, for example, you're trying to send an SMS via AT commands and the modem does something asynchronously (eg. RING indicator, or a periodic signal quality report), and you lose track of who's supposed to get the trailing "OK". Very tedious. In Java I implemented the equivalent of a bidi channel with some timeout tricks for buffering up entire response lines, but it wasn't much fun.