C# 提高集合的添加性能

C# 提高集合的添加性能,c#,performance,collections,C#,Performance,Collections,我正在实施我的收藏: 特殊收集类别: public class SpecialCollection<TId, TName, TValue> : Dictionary<CompositeKey<TId, TName>, TValue> { #region Private fileds private Dictionary<CompositeKey<TId, TName>, TValue> _ba

我正在实施我的收藏:

特殊收集类别:

public class SpecialCollection<TId, TName, TValue> : Dictionary<CompositeKey<TId, TName>, TValue>
    {

        #region Private fileds

        private Dictionary<CompositeKey<TId, TName>, TValue> _baseDictionary = null;
        private ReaderWriterLockSlim _readWriteLockSlim = new ReaderWriterLockSlim();

        #endregion

        #region Constructors

        public SpecialCollection()
        {
            _baseDictionary = new Dictionary<CompositeKey<TId, TName>, TValue>();
        }

        #endregion

        public void Add(CompositeKey<TId, TName> compositeKey, TValue value)
        {
            _readWriteLockSlim.EnterWriteLock();

            try
            {
                _baseDictionary.Add(compositeKey, value);
            }
            catch (ArgumentNullException ex)
            {
                throw ex;
            }
            catch (ArgumentException ex)
            {
                throw ex;
            }
            finally
            {
                _readWriteLockSlim.ExitWriteLock();
            }
        }
}

谢谢

这是我自己测试的,性能几乎没有差别。考虑到您的测试代码,性能上的差异很可能是因为您没有在测试之间重置秒表。正如上面所说:

当秒表实例测量多个间隔时,Stop方法相当于暂停已用时间测量。随后调用Start将从当前经过的时间值恢复测量时间。使用重置方法清除秒表实例中的累计运行时间

因此,只需在测试之间添加一个
sw.Reset()


在我的测试中,我确实通过使用
lock
关键字而不是
readerwriterlocksim
,获得了非常小的性能改进,尽管它可能是随机的。

我自己测试过,性能几乎没有差异。考虑到您的测试代码,性能上的差异很可能是因为您没有在测试之间重置秒表。正如上面所说:

当秒表实例测量多个间隔时,Stop方法相当于暂停已用时间测量。随后调用Start将从当前经过的时间值恢复测量时间。使用重置方法清除秒表实例中的累计运行时间

因此,只需在测试之间添加一个
sw.Reset()

在我的测试中,我确实通过使用
lock
关键字而不是
readerwriterlocksim
,获得了非常小的性能改进,尽管它可能是随机的。

readerwriterlocksim\EnterWriteLock
似乎比简单的C#监视器锁慢得多。由于
ConcurrentDictionary
使用简单锁(与并发级别参数一样多),这可能是性能问题的根源

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        private static object lock1 = new object();
        private static ReaderWriterLockSlim lock2 = new ReaderWriterLockSlim();

        public static int DoLock1(int value)
        {
            lock (lock1)
                return value;
        }

        public static int DoLock2(int value)
        {
            lock2.EnterWriteLock();
            try
            {
                return value;
            }
            finally
            {
                lock2.ExitWriteLock();
            }

        }


        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < 10000000; i++)
            {
                DoLock1(i);
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);

            sw.Reset();
            sw.Start();
            for (int i = 0; i < 10000000; i++)
            {
                DoLock2(i);

            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.IO;
使用System.Linq;
使用System.Net.Sockets;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
命名空间控制台应用程序1
{
班级计划
{
私有静态对象lock1=新对象();
私有静态ReaderWriterLockSlim lock2=新的ReaderWriterLockSlim();
公共静态int DoLock1(int值)
{
锁(锁1)
返回值;
}
公共静态int DoLock2(int值)
{
lock2.EnterWriteLock();
尝试
{
返回值;
}
最后
{
lock2.ExitWriteLock();
}
}
静态void Main(字符串[]参数)
{
秒表sw=新秒表();
sw.Start();
对于(int i=0;i<10000000;i++)
{
DoLock1(i);
}
sw.Stop();
控制台写入线(软件延迟毫秒);
sw.Reset();
sw.Start();
对于(int i=0;i<10000000;i++)
{
DoLock2(i);
}
sw.Stop();
控制台写入线(软件延迟毫秒);
Console.ReadLine();
}
}
}
ReaderWriterLockSlim#EnterWriteLock似乎比简单的C#监视器锁慢得多。由于
ConcurrentDictionary
使用简单锁(与并发级别参数一样多),这可能是性能问题的根源

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        private static object lock1 = new object();
        private static ReaderWriterLockSlim lock2 = new ReaderWriterLockSlim();

        public static int DoLock1(int value)
        {
            lock (lock1)
                return value;
        }

        public static int DoLock2(int value)
        {
            lock2.EnterWriteLock();
            try
            {
                return value;
            }
            finally
            {
                lock2.ExitWriteLock();
            }

        }


        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < 10000000; i++)
            {
                DoLock1(i);
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);

            sw.Reset();
            sw.Start();
            for (int i = 0; i < 10000000; i++)
            {
                DoLock2(i);

            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统诊断;
使用System.IO;
使用System.Linq;
使用System.Net.Sockets;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
命名空间控制台应用程序1
{
班级计划
{
私有静态对象lock1=新对象();
私有静态ReaderWriterLockSlim lock2=新的ReaderWriterLockSlim();
公共静态int DoLock1(int值)
{
锁(锁1)
返回值;
}
公共静态int DoLock2(int值)
{
lock2.EnterWriteLock();
尝试
{
返回值;
}
最后
{
lock2.ExitWriteLock();
}
}
静态void Main(字符串[]参数)
{
秒表sw=新秒表();
sw.Start();
对于(int i=0;i<10000000;i++)
{
DoLock1(i);
}
sw.Stop();
控制台写入线(软件延迟毫秒);
sw.Reset();
sw.Start();
对于(int i=0;i<10000000;i++)
{
DoLock2(i);
}
sw.Stop();
控制台写入线(软件延迟毫秒);
Console.ReadLine();
}
}
}

次要问题-为什么要捕获并重新显示异常?除了代码行的数量之外,没有其他好处这就是为什么您不能在自定义集合中使用
ConcurrentDictionary
?除非这是一项家庭作业,否则您永远不“需要”实现自己的集合。当然,您可能需要实现一些需要集合的功能。但我总是更喜欢现有集合而不是自己的集合。给定代码,唯一合理的优化位置是哈希代码生成和相等性测试,性能将直接取决于这一点,取决于冲突的数量。Ben Aaronson,我不能使用
ConcurrentDictionary
,因为这是一项要求。附带问题-为什么要捕获并重新抛出异常?除了代码行的数量之外,没有其他好处这就是为什么您不能在自定义集合中使用
ConcurrentDictionary
?除非这是一项家庭作业,否则您永远不“需要”实现自己的集合。你
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        private static object lock1 = new object();
        private static ReaderWriterLockSlim lock2 = new ReaderWriterLockSlim();

        public static int DoLock1(int value)
        {
            lock (lock1)
                return value;
        }

        public static int DoLock2(int value)
        {
            lock2.EnterWriteLock();
            try
            {
                return value;
            }
            finally
            {
                lock2.ExitWriteLock();
            }

        }


        static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < 10000000; i++)
            {
                DoLock1(i);
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);

            sw.Reset();
            sw.Start();
            for (int i = 0; i < 10000000; i++)
            {
                DoLock2(i);

            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}