为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
炎炎设计 2023-06-25 14:31:05
我想在多线程环境中测量并发字典与字典+锁的性能。所以我创建了自己的 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];                            });
查看完整描述

1 回答

?
繁星点点滴滴

TA贡献1803条经验 获得超3个赞

您的测试存在多个问题。

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


查看完整回答
反对 回复 2023-06-25
  • 1 回答
  • 0 关注
  • 125 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信