I am trying to design a simple home automation program with Go. My bulbs return streams of messages when their state changes. This can be handled with a callback or may be better with channels in Go.
With callbacks, it is clear that the caller of the light bulb API implements a particular function signature and passes the function to the library. When a bulb changes state or communication error occurs the function will be called. The library will be allocating a done function to be called when the client is no longer interested in updates. For example
type DeviceUpdate = func(Device, error)
type Done = func()
func (client *Client) ObserveDevice(deviceID int, deviceUpdate DeviceUpdate) (Done, error) {
Channels in my case seem to present a nicer abstraction as they can be merged easily, buffering can be added, middleware can easily be woven in etc. I struggle a bit with channel representation of the above declaration. What is the correct convention in Go for this case i.e. channel of data, channel of errors and done/close operation on the whole system.
I am thinking that channels should be allocated by caller similar to functions. This way the caller can instantiate the channel properly and wire middleware before activating the whole set up.
func (client *Client) ObserveDevice(deviceID int, data chan Device, done chan struct{}, err chan error) error {
On the opposite side having the light bulb library allocate channels seems much simpler for the consumer code - you just call a function and no need to allocate 3 channels. As well Go time module seems to go this route bravely e.g. https://golang.org/pkg/time/#After
In my case having the library allocate channels will result in signature like the following
func (client *Client) ObserveDevice(deviceID int) (data chan Device, done chan struct{}, err chan error) {
So what is Go standard practice for channel allocation? Is it caller vs callee or producer vs consumer?
Is the usual practice to have 3 channels when funneling updates from a network stream - data, err and done?
I did some digging in write-ups and videos about channels and concurrency with Go and could not find (perhaps due to laziness) documented best practice. I assume the caller allocating the channels is implied in the examples. See https://gobyexample.com/closing-channels, https://blog.golang.org/pipelines
Aucun commentaire:
Enregistrer un commentaire