【问题标题】:Compare performance of Concurrent Dictionary with Dictionary+Locks比较 Concurrent Dictionary 与 Dictionary+Locks 的性能
【发布时间】:2019-11-24 10:01:15
【问题描述】:

我想在多线程环境中测量并发字典与字典+锁的性能。所以我创建了自己的类型为<int,int[]> 的 SyncDict 类。每当有键匹配时,它会将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];
                            });
                        }
                        finally
                        {
                            cacheLock.ExitWriteLock();
                        }
                        return AddOrUpdateStatus.Updated;
                    }
                }
                else
                {
                    Add(key, value);
                    return AddOrUpdateStatus.Added;
                }
            }
            finally
            {
                cacheLock.ExitUpgradeableReadLock();
            }
        }

        public void Delete(TKey key)
        {
            cacheLock.EnterWriteLock();
            try
            {
                dictionary.Remove(key);
            }
            finally
            {
                cacheLock.ExitWriteLock();
            }
        }

        public enum AddOrUpdateStatus
        {
            Added,
            Updated,
            Unchanged
        };
    }

【问题讨论】:

  • 您使用的是较新的 Slim 锁。如果锁定的周期不长,它们会更快,但会消耗更多的 CPU 资源,并且对于更长的锁定可能会更慢。这将是我的第一个猜测。
  • 有人可以解释投票否决吗?

标签: c# .net performance dictionary


【解决方案1】:

your test 存在多个问题。

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 Method

我建议您修改测试以反映 ConcurrentDictionary 类的预期用途。

【讨论】:

  • 糟糕!我错过了您从 UpdateArray 函数返回一个新数组。第 5 点已经站不住脚了,我的错。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多