StackExchange.Redis - 等待锁定的最佳方式

时间:2015-05-07 22:08:23

标签: redis stackexchange.redis

我有以下方法等待Redis密钥的独占锁定。这种方法有效,但我想知道没有for循环和Thread.Sleep是否有更好的方法。

    /// <summary>
    /// wait up to 2 seconds to achieve a lock!  
    /// The lock is good for a maximum of 3 seconds
    /// </summary>
    /// <param name="codeID"></param>
    internal void WaitForSingleUseLock(CodeID codeID)
    {
        var key = _redemptionRepo.SingleUseCodeLockPrefix + codeID.Value;
        var expiration = TimeSpan.FromSeconds(3);
        for (var i = 0; i < 20; i++)
        {
            var lockAchieved = _cacheRepo.LockTake(key, "1", expiration);
            if (lockAchieved)
            {
                break;
            }
            Thread.Sleep(TimeSpan.FromMilliseconds(100));
        }
    }

2 个答案:

答案 0 :(得分:1)

我唯一可以建议不同的是将pub / sub视为一个旁道(意思是:此外,不是替换)来指示锁可能现在何时可用 - 即发布时释放,并使用sub释放计时器(通过监视器或async-wait-handle)。

除此之外:不。 Redis并不知道待处理的队列。您可能可能使用列表构建一个,但是......

答案 1 :(得分:0)

在考虑了@ Marc的评论并与我的团队讨论Task.Delay()相对于Thread.Sleep()在此背景下的好处之后,我决定将其作为最终解决方案:

    /// <summary>
    /// wait up to 3 seconds to achieve a lock!  
    /// The lock is good for a maximum of 3 seconds
    /// 
    /// Returns the total amount of time until the lock was taken
    /// </summary>
    internal virtual async Task<TimeSpan> WaitForSingleUseLock(CodeID codeID)
    {
        var key = _redemptionRepo.SingleUseCodeLockPrefix + codeID.Value;
        var totalTime = TimeSpan.Zero;
        var maxTime = TimeSpan.FromSeconds(3);
        var expiration = TimeSpan.FromSeconds(3);
        var sleepTime = TimeSpan.FromMilliseconds(50);
        var lockAchieved = false;

        while (!lockAchieved && totalTime < maxTime)
        {
            lockAchieved = _cacheRepo.LockTake(key, "1", expiration);
            if (lockAchieved)
            {
                continue;
            }
            await Task.Delay(sleepTime);
            totalTime += sleepTime;
        }
        return totalTime;
    }