Created
July 6, 2022 22:12
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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