新手初学redis,尝试redis锁的时候,go代码如下:
func main() {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
})
for i := 0; i < 100; i++ {
go func() {
for {
//一直 for 循环抢锁吗?
ok, err := client.SetNX("sync", true, time.Second*5).Result()
if err == nil && ok {
res, err := client.Get("num").Result()
fmt.Printf("num : %s\n", res)
num, err := strconv.Atoi(res)
err = client.Set("num", num+1, 0).Err()
_, err = client.Del("sync").Result()
if err != nil {
log.Println(err)
}
break
}
//time.Sleep(time.Millisecond * 10)
}
}()
}
time.Sleep(time.Second * 20)
}
代码中我开了 100 个协程抢锁,操作一个数据.
我的疑问是,当一个协程抢到了这个 sync 锁,那么其他的 99 个协程, 都一直在不停的在一个循环中重复抢锁吗?这样子是否会对redis产生大量的无意义的请求...网上搜了一下相关的实现demo代码,发现都是类似的
while(true)
{
// xxxxxxx
}
进行抢锁....所以很疑惑,若是真实生产环境也是这样实现嘛....还是我一开始就错了...如果有相关资料或者是搜索关键词,还望大佬指点一二.
看你要实现什么样的锁,或者基于什么样的使用场景,比如说
排它锁
,redis
就实现不了,排它锁
在获取不到锁的情况下会阻塞进入等待队列。在其他进程释放锁时会通知该进程再去获取锁,redis
不提供这种基于key
的通知机制,所以他实现不了排它锁
。不过分布式排它锁
,可以由Zookeeper
实现。另外一种分布式锁的实现方式是通过乐观锁和自旋的实现方式,就是你说的那种方式,不过一般会设置超时时间,也就是
redis
设置key
的ttl
。这样不至于进程一直等待下去。这种锁适应于锁内操作时间比较短,锁竞争不是那么激烈的情况。你说的那种100个进程抢锁的情况,竞争这么激烈,还是用排它锁比较好。