I wish to represent a service that receives triggers to run a particular task, however it only runs that task once at a given time while ignoring concurrent triggers.
My brain came up with an unconventional approach to this problem (it does that sometimes…).
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
once := &sync.Once{}
var trigger = make(chan int)
done := make(chan bool)
onceBody := func(v int) func() {
return func() {
trigger <- v
}
}
go func() {
for {
select {
case v := <-trigger:
fmt.Println("Triggered: ", v)
once = &sync.Once{}
case <-done:
return
}
}
}()
for i := 0; i < 100000; i++ {
i := i
wg.Add(1)
go func() {
defer wg.Done()
once.Do(onceBody(i))
}()
}
wg.Wait()
done <- true
}
I do understand that there are better solutions to this problem. I only wish to understand what problems might arise from this implementation.
I understand that a type of data race is happening with the once
variable, however, I think it might not matter for this particular use-case.
Will the closure’ stale pointer be problematic for the gc?
What problems might arise from this implementation?