【问题标题】:Thread-safe increment/decrement with StackExchange.RedisStackExchange.Redis 的线程安全递增/递减
【发布时间】:2015-07-14 08:45:58
【问题描述】:

我正在使用 StackExchange.Redis 包作为多线程应用程序的共享存储,该应用程序又将同时在多个服务器上运行......所以是多线程的;)

我拥有的一个最简单的用例是我想对一系列键(即 KEY1=4 KEY2=7、KEY3=13 等)保持基本计数。我将制定业务规则来强制执行给定键允许的最大允许值。因此,例如,假设 KEY1 只能达到 5...如果两个线程同时触发试图增加它,我只想让其中一个成功。

我相信我可以通过首先获取当前值然后以该值未更改为条件的事务来完成此操作。这会按我的预期工作吗?有没有更优雅的方法来做到这一点?

    public void Increment(string key) {        
        IDatabase db = redisConn.GetDatabase();
        var val = db.StringGet(key);
        int maxVal = 5; 
        if (Convert.ToInt32(val) < maxVal) {
            var trans = db.CreateTransaction();
            trans.AddCondition(Condition.StringEqual(key, val));
            trans.StringIncrementAsync(key);
            trans.Execute();
        }
    }

PS:很喜欢这个包,合作很愉快

【问题讨论】:

    标签: c# multithreading redis stackexchange.redis


    【解决方案1】:

    是的,应该可以正常工作。但是通过ScriptEvaluate 使用 Lua 脚本可能更容易也更高效。

    注意:使用您当前的代码,您可能需要检查Execute 的响应,如果false 则“从头开始重做”。如果在从 2 移动到 3 时发生线程竞争,使用您当前的代码:更新将被丢弃。这不会是 Lua 脚本的问题。

    【讨论】:

    • 感谢 Marc 的回复,我不熟悉 Lua 脚本的用法,但今晚我会继续阅读。简而言之,是什么使它成为一种更有效的方法?
    • @bruiseruser 无需中断多路复用器来确认断言,也不会因数据更改而导致任何失败;该脚本将是 something 之类的 if tonumber(redis.call('get', KEYS[1])) &lt; 5 then redis.call('incr' , KEYS[1]) end
    • 好的,我认为我的脚本是正确的,但可能没有达到应有的效率,这是我为 Increment 编写的: string script = string.Format("local val = tonumber(redis .call('GET', '{0}')) 或 0 如果 val
    猜你喜欢
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-23
    • 1970-01-01
    • 2013-01-27
    • 1970-01-01
    相关资源
    最近更新 更多