我希望表示一个接收触发器来运行特定任务的服务,但是它仅在给定时间运行该任务一次,而忽略并发触发器。
我的大脑想出了一种非常规的方法来解决这个问题(有时会这样做......)。
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
}
我确实知道这个问题有更好的解决方案。我只想了解这种实现可能会出现什么问题。
我知道
once
变量正在发生一种数据竞争,但是,我认为这对于这个特定的用例来说可能并不重要。
闭包的陈旧指针会给GC带来问题吗? 实施过程中可能会出现什么问题?
要在处理触发器时忽略触发器,请启动一个在循环中接收和丢弃触发器的 goroutine。 处理完成后退出循环。
func ignore(trigger chan int, done chan struct{}) {
for {
select {
case v := <-trigger:
// Discard
case <-done:
return
}
}
}
func run(trigger chan int, done chan struct{}) {
for {
select {
case v := <-trigger:
d := make(chan struct{})
go ignore(trigger, d)
process(v)
d <- struct{}{}
case <-done:
return
}
}
}