這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
工作中碰到緩衝失敗時,資料庫的驚群,本來之前用Redis的SETNX來做鎖處理,後來想想,既然用golang寫了服務,當然可以把鎖直接做在記憶體裡,就自己寫了一小段代碼。
package resourceslockimport ("errors""sync")var (Lock resourcesLock = resourcesLock{lockerMapMtx: new(sync.Mutex),lockerMap: make(map[ResourceTopic]chan void),topicWaitlistMtx: make(map[ResourceTopic]*sync.Mutex),topicWaitlist: make(map[ResourceTopic][]chan bool),} // universal lockvoidMsg void = void{})type ResourceTopic stringtype ProtectCondition func() booltype ReloadFunc func() (interface{}, error)type void struct{}type resourcesLock struct {lockerMapMtx *sync.MutextopicWaitlistMtx map[ResourceTopic]*sync.MutexlockerMap map[ResourceTopic](chan void)topicWaitlist map[ResourceTopic][](chan bool)}func (self *resourcesLock) Protect(topic ResourceTopic, cond *ProtectCondition, reload *ReloadFunc) error {if (*cond)() == true {return nil}var err errorself.createLockChn(topic)select {case <-self.lockerMap[topic]:_, err = (*reload)()if err != nil {self.notifyError(topic)} else {self.notifySuccess(topic)}self.lockerMap[topic] <- voidMsgdefault:if !<-self.addToWaitlist(topic) {err = errors.New("Resource is not refreshed.")}}return err}func (self *resourcesLock) createLockChn(topic ResourceTopic) {self.lockerMapMtx.Lock()_, ok := self.lockerMap[topic]if !ok {ch := make(chan void, 1)ch <- voidMsgself.lockerMap[topic] = chself.topicWaitlistMtx[topic] = new(sync.Mutex)}self.lockerMapMtx.Unlock()}func (self *resourcesLock) addToWaitlist(topic ResourceTopic) <-chan bool {ch := make(chan bool)self.topicWaitlistMtx[topic].Lock()self.topicWaitlist[topic] = append(self.topicWaitlist[topic], ch)self.topicWaitlistMtx[topic].Unlock()return ch}func (self *resourcesLock) notifyError(topic ResourceTopic) {self.notify(topic, false)}func (self *resourcesLock) notifySuccess(topic ResourceTopic) {self.notify(topic, true)}func (self *resourcesLock) notify(topic ResourceTopic, suc bool) {self.topicWaitlistMtx[topic].Lock()for i, c := range self.topicWaitlist[topic] {if suc {c <- true} else {c <- false}self.topicWaitlist[topic][i] = nil}self.topicWaitlist[topic] = self.topicWaitlist[topic][:0]self.topicWaitlistMtx[topic].Unlock()}