回答我自己的问题,因为我昨晚深夜遇到了一些解决方案。
对我来说最简单的答案是使用 sync.Mutex 变量来锁定和解锁油门功能,以确保我不会意外地同时击中它。另一种选择是将我的节流服务移动到它自己的 goroutine 函数中(从而消除并发调用)并与通道通信节流/OK,但对于这个应用程序来说,Mutex 是一个更清洁的解决方案。
以下是寻找类似解决方案的工作代码的简化版本:
package main
import (
"fmt"
"time"
"sync"
)
type tStruct struct {
delay time.Duration
last time.Time
lock sync.Mutex //this will be our locking variable
}
func (t *tStruct) createT() *tStruct {
return &tStruct {
delay: 500*time.Millisecond,
last: time.Now(),
}
}
func (t *tStruct) throttle(th int) {
//we lock our function, and any other routine calling this function will block.
t.lock.Lock()
//and we'll defer an unlock, so when we exit the throttle, we'll be ready for another call.
defer t.lock.Unlock()
fmt.Printf("\tThread %v Entering Throttle Check.\n", th)
defer fmt.Printf("\tThread %v Leaving Throttle Check.\n", th)
for {
p := time.Now().Sub(t.last)
if p < t.delay {
fmt.Printf("\tThread %v Sleeping %v.\n", th, t.delay-p)
time.Sleep(t.delay-p)
} else {
fmt.Printf("\tThread %v No longer Throttled.\n", th)
t.last = time.Now()
break
}
}
}
func (t *tStruct) worker(rch <-chan string, sch chan<- string, th int) {
fmt.Printf("Thread %v starting up.\n", th)
defer fmt.Printf("Thread %v Dead.\n", th)
sch <-"READY"
for {
r := <-rch
fmt.Printf("Thread %v received %v\n", th, r)
switch r {
case "STOP":
fmt.Printf("Thread %v returning.\n", th)
sch <-"QUITTING"
return
default:
fmt.Printf("Thread %v processing %v.\n", th, r)
t.throttle(th)
fmt.Printf("Thread %v done with %v.\n", th, r)
sch <-"OK"
}
}
}
func main() {
ts := tStruct{}
ts.delay = 500*time.Millisecond
ts.last = time.Now()
sch := make(chan string)
rch := make(chan string)
tC := 3
tA := 0
fmt.Println("Starting Threads")
for i:=1; i<(tC+1); i++ {
go ts.worker(sch, rch, i)
r := <-rch
if r=="READY" {
tA++
} else {
fmt.Println("ERROR not READY")
}
}
fmt.Println("Feeding All Threads")
for i:=1; i<(tC+1); i++ {
sch <- "WORK"
}
fmt.Println("Listening for threads")
for tA > 0{
r := <-rch
switch r {
case "QUITTING":
tA--
fmt.Println("main received QUITTING")
continue
case "OK":
fmt.Println("main received OK")
sch <-"STOP"
continue
default:
fmt.Println("Shouldn't be here!!!")
}
}
}