golang实现Redis分布式自旋锁+本地自旋锁

Esta ·
更新时间:2024-09-20
· 728 次阅读

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



自旋锁 redis分布式 自旋 golang Redis

需要 登录 后方可回复, 如果你还没有账号请 注册新账号