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();
}
}
}