Skip to content

Instantly share code, notes, and snippets.

@gigablah
Last active January 20, 2016 04:38
Show Gist options
  • Save gigablah/80d7160f3577edc153c9 to your computer and use it in GitHub Desktop.
Save gigablah/80d7160f3577edc153c9 to your computer and use it in GitHub Desktop.
Debouncing Go channels
// Reference: https://gist.github.com/leolara/d62b87797b0ef5e418cd
package main
import (
"fmt"
"time"
)
type APIEvents struct {
Status string
ID int
}
var start time.Time
func init() {
start = time.Now()
}
func doSomething() {
fmt.Printf("[%s] Doing expensive operation...\n", time.Since(start))
time.Sleep(100 * time.Millisecond)
}
func main() {
eventChan := make(chan *APIEvents, 100)
defer close(eventChan)
done := make(chan struct{})
defer close(done)
debouncedChan := debounce(100 * time.Millisecond, 500 * time.Millisecond, eventChan)
defer close(debouncedChan)
go func() {
time.Sleep(100 * time.Millisecond)
fmt.Printf("[%s] Starting to send events...\n", time.Since(start))
for i := 0; i < 30; i++ {
eventChan <- &APIEvents{"start", i}
time.Sleep(30 * time.Millisecond)
}
time.Sleep(500 * time.Millisecond)
for i := 30; i < 130; i++ {
eventChan <- &APIEvents{"start", i}
time.Sleep(10 * time.Millisecond)
}
time.Sleep(500 * time.Millisecond)
eventChan <- &APIEvents{"stop", 130}
time.Sleep(500 * time.Millisecond)
done <- struct{}{}
}()
OUTER:
for {
select {
case <-done:
break OUTER
case event := <-debouncedChan:
if event == nil {
break
}
if event.Status == "start" || event.Status == "stop" {
fmt.Printf("[%s] Received debounced event %s with ID %d\n", time.Since(start), event.Status, event.ID)
doSomething()
}
}
}
fmt.Printf("[%s] Exited loop...\n", time.Since(start))
time.Sleep(100 * time.Millisecond)
fmt.Printf("[%s] Done.\n", time.Since(start))
}
func debounce(min time.Duration, max time.Duration, input chan *APIEvents) chan *APIEvents {
output := make(chan *APIEvents)
go func() {
var (
buffer *APIEvents
ok bool
minTimer <-chan time.Time
maxTimer <-chan time.Time
)
// Start debouncing
for {
select {
case buffer, ok = <-input:
if !ok {
return
}
fmt.Printf("[%s] Received raw event %s with ID %d\n", time.Since(start), buffer.Status, buffer.ID)
minTimer = time.After(min)
if maxTimer == nil {
maxTimer = time.After(max)
}
case <-minTimer:
fmt.Printf("[%s] Min timer is up!\n", time.Since(start))
minTimer, maxTimer = nil, nil
output <- buffer
case <-maxTimer:
fmt.Printf("[%s] Max timer is up!\n", time.Since(start))
minTimer, maxTimer = nil, nil
output <- buffer
}
}
}()
return output
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment