4

Booksleeve 是否支持 CAS 操作(即 Redis WATCH命令)?例如,如何实现以下内容?

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

当多个线程试图用相同的数据修改同一个对象时,我需要这个来避免竞争条件。

4

1 回答 1

2

目前在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优化为可靠快速,因此不会影响其他调用者。

于 2012-08-01T21:35:56.003 回答