比较并发字典与字典+锁的性能

我想在多线程环境中测量并发字典与字典+锁的性能。所以我创建了自己的 SyncDict 类型类<int,int[]>。每当有键匹配时,它就会将int[]数组值添加到自身中,并在更新值时使用 ReaderWriterLockSlim 锁定整个字典。

我通过并发字典复制了代码,我主要使用AddOrUpdate()方法。

整个控制台应用程序代码可以在这里找到https://dotnetfiddle.net/1kFbGy只需将代码复制粘贴到控制台应用程序中即可运行。它不会运行小提琴

使用相同的输入运行两个代码后,我发现运行时间有相当大的差异。例如,对于我的机器上的一次特定运行,并发字典花费了 4.5 秒,而 SyncDict 花费了不到 1 秒。

我想知道解释上述运行时间的任何想法/建议。我在这里做错了什么吗?

class SyncDict<TKey>

    {

        private ReaderWriterLockSlim cacheLock;

        private Dictionary<TKey, int[]> dictionary;

        public SyncDict()

        {

            cacheLock = new ReaderWriterLockSlim();

            dictionary = new Dictionary<TKey, int[]>();

        }


        public Dictionary<TKey, int[]> Dictionary

        {

            get { return dictionary; }

        }


        public int[] Read(TKey key)

        {

            cacheLock.EnterReadLock();

            try

            {

                return dictionary[key];

            }

            finally

            {

                cacheLock.ExitReadLock();

            }

        }


        public void Add(TKey key, int[] value)

        {

            cacheLock.EnterWriteLock();

            try

            {

                dictionary.Add(key, value);

            }

            finally

            {

                cacheLock.ExitWriteLock();

            }

        }


        public AddOrUpdateStatus AddOrUpdate(TKey key, int[] value)

        {

            cacheLock.EnterUpgradeableReadLock();

            try

            {

                int[] result = null;

                if (dictionary.TryGetValue(key, out result))

                {

                    if (result == value)

                        return AddOrUpdateStatus.Unchanged;

                    else

                    {

                        cacheLock.EnterWriteLock();

                        try

                        {

                            Parallel.For(0, value.Length,

                            (i, state) =>

                            {

                                result[i] = result[i] + value[i];

                            });



炎炎设计
浏览 126回答 1
1回答

繁星点点滴滴

您的测试存在多个问题。1) 您正在使用大约 150.000 个不同的键填充字典,所有键都具有相同的值。2) 所有条目的共享值是一个包含 30.000 个整数的数组,并且您将在一半的调用中更新其中的每个元素AddOrUpdate。但这仅在您测试时才会发生ConcurrentDictionary。在SyncDict测试中,有一个条件if (result == value) return AddOrUpdateStatus.Unchanged会跳过所有更新(因为该值是共享的)。3)您正在使用不同的随机输入来提供两个测试。4) 您正在使用循环更新数组Parallel.For,同时已经处于外部Parallel.For循环中,从而过度并行化您的工作负载。5) 调用该方法时,AddOrUpdate您忽略了记录的事实,即该updateValueFactory函数以线程不安全的方式调用,并且由于多个函数AddOrUpdate是同步执行的并且该值是共享的,因此您正在破坏该值的状态。在锁之外调用委托updateValueFactory以避免在锁下执行未知代码可能引起的问题。ConcurrentDictionary.AddOrUpdate 方法我建议您修改测试以反映该类的预期用途ConcurrentDictionary。
打开App,查看更多内容
随时随地看视频慕课网APP