golang使用redis的setnx实现了一个自选锁,有key超时,同时也有我们调用redis链接时的超时。
package locker import ( "context" "github.com/go-redis/redis" "runtime" "time" ) type Lock struct { resource string value interface{} timeout time.Duration redisCli *redis.ClusterClient //这个是链接redis集群的cli,可以自行修改 } func NewRedis(redisCli *redis.ClusterClient, resource string, value interface{}, timeOut time.Duration) *Lock { return &Lock{ resource: resource, value: value, timeout: timeOut, redisCli: redisCli, } } func (lock *Lock) TryLock() (ok bool, err error) { ok, err = lock.redisCli.SetNX(lock.resource, lock.value, lock.timeout).Result() //log.Printf("resource:%s, timeout:%v, ok:%v, err:%v\n", lock.resource, lock.timeout, ok, err) return } func (lock *Lock) Unlock() (err error) { err = lock.redisCli.Del(lock.resource).Err() return } func (lock *Lock) SpinLockUntilTimeOut(ctx context.Context, d time.Duration) (timeOut bool, err error) { var ( now time.Time ok bool ) endTime := time.Now().Add(d) for { select { case <-ctx.Done(): timeOut = true //log.Printf("SpinLockUntilTimeOut at ctx.Done()") return default: now = time.Now() if now.After(endTime) { timeOut = true //log.Printf("SpinLockUntilTimeOut at d") return } ok, err = lock.TryLock() if err != nil { return } if ok { return } else { runtime.Gosched() } } } }
用golang实现了一个内存版的
package locker import ( "context" ) var lockers map[string]map[uint64]chan interface{} var addLock chan lockImpl var delLock chan lockImpl var tranceId uint64 type lockImpl struct { delId uint64 addId chan uint64 wait chan interface{} key string } func init() { lockers = make(map[string]map[uint64]chan interface{}) addLock = make(chan lockImpl) delLock = make(chan lockImpl) run() } func run() { go func() { var ( ok1, ok2 bool addLs, delLs map[uint64]chan interface{} ) for { select { case add := <- addLock: if addLs, ok1 = lockers[add.key]; !ok1 { addLs = make(map[uint64]chan interface{}) } tranceId++ addLs[tranceId] = add.wait lockers[add.key] = addLs add.addId <- tranceId close(add.addId) if len(addLs) == 1 { add.wait <- struct {}{} close(add.wait) } case del := <- delLock: if delLs, ok2 = lockers[del.key]; ok2 { delete(delLs, del.delId) for _, v := range delLs { v <- struct {}{} close(v) break } } } } }() } type Memory struct { key string id uint64 } func (m *Memory)SLock(ctx context.Context) (timeOut bool, err error) { l := lockImpl{ addId: make(chan uint64, 1), wait: make(chan interface{}, 1), key: m.key, } addLock <- l m.id = <- l.addId select { case <-l.wait: return case <-ctx.Done(): timeOut = true return } } func (m *Memory)UnSLock() (err error) { l := lockImpl{ delId:m.id, key: m.key, } delLock<-l return } func NewMemory(path string) *Memory { return &Memory{ key:path, } }
作者:weixin_30746129