Skip to content

Instantly share code, notes, and snippets.

@bunsenmcdubbs
Created July 6, 2022 22:12
Show Gist options
  • Save bunsenmcdubbs/7feeae056ac0a47885b73f5123a4bc21 to your computer and use it in GitHub Desktop.
Save bunsenmcdubbs/7feeae056ac0a47885b73f5123a4bc21 to your computer and use it in GitHub Desktop.
Simple channel-less pub/sub pattern for go which avoids using channels in the public API
package main
import (
"fmt"
"sync"
)
type Subscriber struct {
callback func()
}
type PubSub struct {
mu sync.Mutex
subs map[*Subscriber]struct{}
}
func NewPubSub() *PubSub {
return &PubSub{
subs: make(map[*Subscriber]struct{}),
}
}
// Subscribe returns a new Subscriber who's callback function is invoked whenever
// PubSub's Notify() function is called. The callback function MUST be nonblocking.
func (p *PubSub) Subscribe(callback func()) *Subscriber {
p.mu.Lock()
defer p.mu.Unlock()
s := &Subscriber{callback}
p.subs[s] = struct{}{}
return s
}
func (p *PubSub) Unsubscribe(s *Subscriber) {
p.mu.Lock()
defer p.mu.Unlock()
delete(p.subs, s)
}
func (p *PubSub) Notify() {
p.mu.Lock()
defer p.mu.Unlock()
for s, _ := range p.subs {
s.callback()
}
}
func main() {
p := NewPubSub()
s1 := p.Subscribe(func() {
fmt.Println("s1 notified!")
})
fmt.Println("first notification (s1 only)")
p.Notify()
s2 := p.Subscribe(func() {
fmt.Println("s2 notified!!")
})
fmt.Println("second notification (s1 and s2)")
p.Notify()
p.Unsubscribe(s1)
fmt.Println("third notification (s2 only)")
p.Notify()
p.Unsubscribe(s2)
fmt.Println("fourth notification (none)")
p.Notify()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment