beetlex-io / BeetleX.Redis

A high-performance async/non-blocking redis client components for dotnet core,default data formater json protobuf and messagepack,support ssl
Apache License 2.0
186 stars 35 forks source link

Deadlock on Set #14

Open BertusVanZyl opened 4 years ago

BertusVanZyl commented 4 years ago

I am experiencing some kind of deadlock. I am doing some basic proof of concept testing in an attempt to use redis as a distributed concurrency management scheme.

When the Set command is inside the nested await, it appears to lock.

Here is a sample (a simple console app) :

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="BeetleX.Redis" Version="0.9.5" />
  </ItemGroup>

</Project>
class Program
    {
        static async Task Main(string[] args)
        {
            RedisDB DB = new RedisDB(1);
            DB.Host.AddWriteHost("xxxxx", 6379, false);
            var resultList = new List<string>();
            await DB.Del("aaa");
            var list = new List<ValueTask<string>>();
            for (int i = 0; i < 1; i++)
            {
                await DoTest(10);
            }
            foreach (var l in list)
            {
                resultList.Add(await l);
            }
            var result = resultList.GroupBy(x => x).Select(x => new { V = x.Key, C = x.Count() });
        }

        public static async Task DoTest(int count)
        {
            RedisDB DB = new RedisDB(1);
            DB.Host.AddWriteHost("xxxxxx", 6379, false);
            var resultList = new List<string>();

            var list = new List<ValueTask<string>>();
            for (int i = 0; i < count; i++)
            {
                var r = await DB.Set("aaa", 1, seconds: null, nx: true);
                resultList.Add(r);
            }
            foreach (var l in list)
            {
                resultList.Add(await l);
            }
            var result = resultList.GroupBy(x => x).Select(x => new { V = x.Key, C = x.Count() });
        }
    }
beetlex-io commented 4 years ago

RedisDB is thread safe, can be defined as a static variable. modify the code to run successfully

    class Program
    {
        static RedisDB DB = new RedisDB(1);

        static async Task Main(string[] args)
        {
            DB.Host.AddWriteHost("192.168.2.19", 6379, false);
            var resultList = new List<string>();
            await DB.Del("aaa");
            var list = new List<ValueTask<string>>();
            for (int i = 0; i < 1; i++)
            {
                await DoTest(10);
            }
            foreach (var l in list)
            {
                resultList.Add(await l);
            }
            var result = resultList.GroupBy(x => x).Select(x => new { V = x.Key, C = x.Count() });
            Console.WriteLine("completed!");
            Console.Read();
        }

        public static async Task DoTest(int count)
        {
            var resultList = new List<string>();
            var list = new List<ValueTask<string>>();
            for (int i = 0; i < count; i++)
            {
                var r = DB.Set("aaa", 1, seconds: null, nx: true);
                list.Add(r);
            }
            foreach (var l in list)
            {
                resultList.Add(await l);
            }

            foreach (var item in resultList)
                Console.WriteLine($"{(item == null ? "null" : item)}");
        }
    }

image

BertusVanZyl commented 4 years ago

Changing the code like you suiggested removes the deadlock problem. However, I want to test concurrencly from different processes, and for that I need to create more than one connection. The moment I create another connection, and attempt to call SET on it, it locks up.

I would I create more than one RedisDB, to simulate connections from different processes?

beetlex-io commented 4 years ago

RedisDB internal is using connection pool access redis, you can define an instance to operate in multiple threads.