Skip to content

验证 Redis INCR 命令的原子性

🏷️ Redis

想确认一下 INCR 命令是不是原子性的,所以写了段代码试了一下。

安装所需包

额外安装了一个 Args 包用来解析命令行参数,具体文档参考 这里

powershell
Install-Package StackExchange.Redis -Version 2.0.601
Install-Package Args -Version 1.2.1

示例代码

同时对变量 varCount 执行 ++ 操作来跟 Redis 做对比。

csharp
using StackExchange.Redis;
using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace RedisMultiThreadsIncrement
{
    class Program
    {
        static void Main(string[] args)
        {
            var parameter = Args.Configuration.Configure<Parameter>().CreateAndBind(args);

            var sw = Stopwatch.StartNew();

            ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost");
            IDatabase db = redis.GetDatabase();

            string counterKey = "counter";
            int varCount = 0;
            db.StringSet(counterKey, 0);

            Task[] tasks = new Task[parameter.TaskCount];
            for (int i = 0; i < parameter.TaskCount; i++)
            {
                tasks[i] = Task.Run(() =>
                {
                    for (int j = 0; j < parameter.PerTaskCount; j++)
                    {
                        db.StringIncrement(counterKey);
                        varCount++;
                    }
                });
            }

            Task.WaitAll(tasks);

            Console.WriteLine($"Last counter result: {db.StringGet(counterKey)}");
            Console.WriteLine($"Last varCount: {varCount}");

            sw.Stop();

            Console.WriteLine($"Increment {parameter.TaskCount} * {parameter.PerTaskCount} 次(耗时:{sw.ElapsedMilliseconds} ms)");

            Console.WriteLine("press <enter> to exit.");
            Console.ReadLine();
        }
    }

    /// <summary>
    /// 参数模型
    /// </summary>
    class Parameter {
        /// <summary>
        /// 线程数
        /// </summary>
        public int TaskCount { get; set; } = 10;
        /// <summary>
        /// 每个线程的计数次数
        /// </summary>
        public int PerTaskCount { get; set; } = 100;
    }
}

执行结果

执行了数次,Redis 最后的结果都是相同的,而变量 varCount 的值则几乎每次都不相同,而且没有一次是正确的结果。

powershell
>dotnet run /TaskCount 100 /PerTaskCount 1000
Last counter result: 100000
Last varCount: 99962
Increment 100 * 1000 次(耗时:5251 ms)
press <enter> to exit.

总结

很明显可以看出 INCR 是原子性的自增操作。

参考官方文档 INCR key,其中确实提到了 INCR 是 原子的增加操作。

The counter pattern is the most obvious thing you can do with Redis atomic increment operations. The idea is simply send an INCR command to Redis every time an operation occurs.