0

I'm wondering what is the proper way to handle the concept of "events" (with notifiers/receivers) in Golang. I suppose I need to use channels but not sure about the best way.

Specifically, I have the program below with two workers. Under certain conditions, "worker1" goes in and out of a "fast mode" and notify this via channels. "worker2" can then receive this event. This works fine, but then the two workers are tightly coupled. In particular, if worker2 is not running, worker1 gets stuck waiting when writing to the channel.

What would be the best way in Golang to implement this logic? Basically, one worker does something and notify any other worker that it has done so. Whether other workers listen to this event or not must not block worker1. Ideally, there could be any number of workers that could listen to this event.

Any suggestion?

var fastModeEnabled = make(chan bool)
var fastModeDisabled = make(chan bool)

func worker1() {
    mode := "normal"
    for {
        // under some conditions:
        mode := "fast"
        fastModeEnabled <- true

        // later, under different conditions:
        mode := "normal"
        fastModeDisabled <- true
    }
}

func worker2() {
    for {
        select {

        case <-fastModeEnabled:

            fmt.Println("Fast mode started")

        case <-fastModeDisabled:

            fmt.Println("Fast mode ended")

        }
    }
}

func main() {
    go worker2()
    go worker1()

    for {}
}
laurent
  • 88,262
  • 77
  • 290
  • 428
  • Would [`sync.Condition`](https://golang.org/pkg/sync/#Cond) be what you're looking for? – JimB Aug 31 '16 at 15:11
  • Possible duplicate of [Property change notification in go](http://stackoverflow.com/questions/29488010/property-change-notification-in-go) – icza Aug 31 '16 at 15:55
  • Maybe a buffered channel will help if the only concern is blocking writes to the channel. Admittedly not a good solution because you'll need to make some pre-estimate about size of buffer. Edit - ignore that - just noticed they're bool channels. – Sridhar Aug 31 '16 at 16:11

1 Answers1

3

Use a non-blocking write to the channel. This way if anyone is listening they receive it. If there is no one listening it doesn't block the sender, although the event is lost.

You could use a buffered channel so that at least some events are buffered if you need that.

You implement a non-blocking send by using the select keyword with a default case. The default makes it non-blocking. Without the default case a select will block until one of its channels becomes usable.

Code snippit:

select {
    case ch <- event:
        sent = true
    default:
        sent = false
}
Zan Lynx
  • 53,022
  • 10
  • 79
  • 131