小编典典

StackExchange.Redis-LockTake / LockRelease的用法

redis

我将Redis与StackExchange.Redis一起使用。我有多个线程将在某个时候访问并编辑同一键的值,因此我需要同步数据的操作。

查看可用的功能,我发现有两个功能,即TakeLock和ReleaseLock。但是,这些函数同时具有键和值参数,而不是预期要锁定的单个键。GitHub上的intellisene文档和源代码没有解释如何使用LockTake和LockRelease函数,以及如何传递键和值参数。

问:StackExchange.Redis中LockTake和LockRelease的正确用法是什么?

我打算做的伪代码示例:

//Add Items Before Parallel Execution
redis.StringSet("myJSONKey", myJSON);

//Parallel Execution
Parallel.For(0, 100, i =>
    {
        //Some work here
        //....

        //Lock
        redis.LockTake("myJSONKey");

        //Manipulate
        var myJSONObject = redis.StringGet("myJSONKey");
        myJSONObject.Total++;
        Console.WriteLine(myJSONObject.Total);
        redis.StringSet("myJSONKey", myNewJSON);

        //Unlock
        redis.LockRelease("myJSONKey");

        //More work here
        //...
    });

阅读 1940

收藏
2020-06-20

共1个答案

小编典典

锁由三部分组成:

  • 密钥(数据库中锁的唯一名称)
  • 值(一个调用方定义的令牌,该令牌可用于指示谁“拥有”该锁,并检查是否正确完成了释放和扩展该锁)
  • 持续时间(故意锁是有限持续时间的东西)

如果没有其他价值,guid可能会做出合适的“价值”。我们倾向于使用机器名(如果多个进程可能在同一台机器上竞争,则使用机器名的简化版本)。

另外,请注意,锁定只是一种 推测 ,而不是 阻塞 。您很可能 无法 获取锁,因此您可能需要对此进行测试并可能添加一些重试逻辑。

一个典型的例子可能是:

RedisValue token = Environment.MachineName;
if(db.LockTake(key, token, duration)) {
    try {
        // you have the lock do work
    } finally {
        db.LockRelease(key, token);
    }
}

请注意,如果工作很长(尤其是循环),则可能需要LockExtend在中间添加一些偶尔的调用-再次记住要检查是否成功(以防超时)。

还要注意, 所有 单独的redis命令都是原子的,因此您不必担心两个谨慎的操作会相互竞争。对于更复杂的多操作单元,可以选择 事务脚本

2020-06-20