Booksleeve 是否支持 CAS 操作(即 Redis WATCH命令)?例如,如何实现以下内容?
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
当多个线程试图用相同的数据修改同一个对象时,我需要这个来避免竞争条件。
Booksleeve 是否支持 CAS 操作(即 Redis WATCH命令)?例如,如何实现以下内容?
WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC
当多个线程试图用相同的数据修改同一个对象时,我需要这个来避免竞争条件。
目前在nuget中,我不这么认为。由于 BookSleeve通常用作多路复用器,这使得“手表”无法使用。我可以添加它,您必须在操作期间将使用限制为单个调用者(每个 BookSleeve 连接)。
现在已经改变了;如果我们想手动实现INCR
(根据您的示例),我们可以使用:
// note this could be null if the old key didn't exist
var oldVal = await connection.Strings.GetInt64(db, key);
var newVal = (oldVal ?? 0) + 1;
using (var tran = connection.CreateTransaction())
{
// check hasn't changed (this handles the WATCH, a checked GET,
// and an UNWATCH if necessary); note tat conditions are not sent
// until the Execute is called
tran.AddCondition(Condition.KeyEquals(db, key, oldVal));
// apply changes to perform assuming the conditions succeed
tran.Strings.Set(db, key, newVal); // the SET
// note that Execute includes the MULTI/EXEC, assuming the conditions pass
if (!await tran.Execute()) return null; // aborted; either a pre-condition
// failed, or a WATCH-key was changed
return newVal; // successfully incremented
}
显然,您可能希望在重复的(在合理的范围内)循环中执行它,以便如果它因为 而中止WATCH
,您可以从头开始重做。
这与您的示例略有不同,因为它实际上是这样(假设值在 initialGET
和 second之间没有改变GET
):
val = GET mykey
newval = (val ?? 0) + 1
WATCH mykey
chk = GET mykey // and verifies chk == val as part of the Execute
MULTI
SET mykey $newval
EXEC
请注意,EXEC
如果值在WATCH
和之间发生更改,仍然可以报告取消EXEC
;或(如果它在两个s 之间发生了变化):GET
val = GET mykey
newval = (val ?? 0) + 1
WATCH mykey
chk = GET mykey // and verifies chk == val as part of the Execute
UNWATCH
不同之处在于GET
,但这是它可以与多路复用器一起工作的唯一方式 - 即Execute
优化为可靠快速,因此不会影响其他调用者。