當遇到一個協程寫,其它協程處于等待讀取的時候場景的時候,需要使用標準庫中的sync.cond
才能優雅的解決。
package main
import (
"log"
"net/http"
"sync"
)
type Notifier struct {
m map[string]string
cond *sync.Cond
}
func NewNotifier(m map[string]string) *Notifier {
return &Notifier{
m: m,
cond: sync.NewCond(&sync.Mutex{}),
}
}
func listen(index int, name string, notifier *Notifier) {
v := notifier.m[name]
for {
notifier.cond.L.Lock()
for v == notifier.m[name] {
notifier.cond.Wait()
}
v = notifier.m[name]
log.Printf("index:%d received %s changed:%s", index, name, v)
notifier.cond.L.Unlock()
}
}
func broadcast(name string, value string, notifier *Notifier) {
notifier.cond.L.Lock()
notifier.m[name] = value
notifier.cond.L.Unlock()
notifier.cond.Broadcast()
}
func main() {
m := map[string]string{}
name := "time"
n := NewNotifier(m)
for i := -1; i < 3; i++ {
i := i
go func() {
listen(i, name, n)
}()
}
http.HandleFunc("/test", func(writer http.ResponseWriter, request *http.Request) {
time := request.URL.Query().Get("time")
broadcast(name, time, n)
})
http.ListenAndServe(":8090", nil)
}
當通過瀏覽器訪問http://localhost:8090/test?time=33
時候,會觸發listen
寫入協程,然后會通過broadcast
來通過其它等待的協程。
通過更換time
的值,可以看到,我們期望的是當time
的值相比之前發生變化的時候,才能看到日志輸出。