在redis中存在异步问题

时间:2017-08-31 07:58:31

标签: redis

如果redis是单线程服务器,为什么结果不是100000?我认为这不是redis的问题,但我想知道原因。感谢。

        RedisConnection.Default.Database.StringSet("mykey1", 0);
        Parallel.For(0, 50000, new ParallelOptions { MaxDegreeOfParallelism = 2 }, (i) =>
        {
            var number = RedisConnection.Default.Database.StringGet("mykey1");
            int result = int.Parse(number);
            RedisConnection.Default.Database.StringSet("mykey1", result + 1);

        });
        Console.WriteLine("Result" + RedisConnection.Default.Database.StringGet("mykey1"));

2 个答案:

答案 0 :(得分:1)

您可以使用MULTI / EXEC来避免此问题。它将确保两个命令不会被其他命令拆分。这将是一笔交易。

答案 1 :(得分:0)

由于您对Redis进行了两次单独调用,而没有使用事务块(MULTI / EXEC),因此StringGetStringSet操作不是原子操作。执行线程可以交错Get和Set操作。

考虑一个可能的执行顺序:

  1. Thread1读取myKey1 = 40
  2. Thread2读取myKey1 = 40
  3. Thread2用41
  4. 写myKey
  5. Thread2读取myKey1 = 41
  6. Thread2用42
  7. 写myKey
  8. Thread1用41
  9. 写myKey1

    编写此代码的正确方法是通过调用StringGet替换对StringSetStringIncrement的单独调用:

        RedisConnection.Default.Database.StringSet("mykey1", 0);
        Parallel.For(0, 50000, new ParallelOptions { MaxDegreeOfParallelism = 2 }, (i) =>
        {
            RedisConnection.Default.Database. StringIncrement("mykey1");
        });
        Console.WriteLine("Result" + RedisConnection.Default.Database.StringGet("mykey1"));