我将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 //... });
锁由三部分组成:
如果没有其他价值,guid可能会做出合适的“价值”。我们倾向于使用机器名(如果多个进程可能在同一台机器上竞争,则使用机器名的简化版本)。
另外,请注意,锁定只是一种 推测 ,而不是 阻塞 。您很可能 无法 获取锁,因此您可能需要对此进行测试并可能添加一些重试逻辑。
一个典型的例子可能是:
RedisValue token = Environment.MachineName; if(db.LockTake(key, token, duration)) { try { // you have the lock do work } finally { db.LockRelease(key, token); } }
请注意,如果工作很长(尤其是循环),则可能需要LockExtend在中间添加一些偶尔的调用-再次记住要检查是否成功(以防超时)。
LockExtend
还要注意, 所有 单独的redis命令都是原子的,因此您不必担心两个谨慎的操作会相互竞争。对于更复杂的多操作单元,可以选择 事务 和 脚本 。