【发布时间】:2019-02-07 21:14:24
【问题描述】:
我正在使用 Redis 创建一个算法,用于从一个范围内声明未使用的整数。我的解决方案基于我对this SO 问题的回答。
这个解决方案使用BITPOS和BITSET,为了避免竞争条件,我也使用WATCH/MULTI/EXEC。为了测试并发方面,我创建了一个 bash 脚本,它同时尝试并行查找空闲数 10 次,以调查EXEC 命令的可能结果。
我发现EXEC 从未返回 null,即使监视的密钥已被另一个客户端修改。我添加了延迟,以便有足够的时间引发并发修改,该修改应该触发监视机制,因此 EXEC 失败,但它没有。
所以基本上我有这段代码:
while (true) {
WATCH mykey
number = BITPOS mykey, 0
if (number > maxNumber) THROW ERROR
(deliberate delay)
MULTI
SETBIT mykey, number, 1
if EXEC != null return number
}
还有一个在 10 个不同进程中为 N = 1..10 调用 SETBIT mykey, N, 1 的循环。
我发现EXEC 从未返回 null,即使在监视的时间段内该密钥确实被另一个进程修改了。
问题:
- 基于 BIT 的 Redis 命令是否根本不支持
WATCH? - 如果支持,为什么在这种情况下不触发?我是否错误地测试/激发了它?据我了解,
WATCH应该使EXEC失败,如果密钥在观察期间被另一个客户端/连接修改,并从 10 个不同的 Linux 进程调用它,每个进程创建它自己的连接,似乎符合这个要求? - 在这种特殊情况下,
WATCH和MULTI是否真的提供了什么?BITSET返回该位的先前值,因此不应该简单地通过以下伪代码算法来保证原子性:
while (true) {
number = BITPOS mykey, 0
if (number > maxNumber) THROW ERROR
wasUsed = SETBIT mykey, number, 1
if (!wasUsed) {
return number
}
}
【问题讨论】:
标签: concurrency redis watch bitset