C# 将KeyValuePair作为密钥的字典(C.NET)的性能糟糕

C# 将KeyValuePair作为密钥的字典(C.NET)的性能糟糕,c#,.net,dictionary,C#,.net,Dictionary,在我正在编写的一个应用程序中,我有两组可能很大的数据需要相互映射。一个是从web服务返回的列表,另一个是DataTable。我需要获取列表中每个项目的ANSI或ISO编号,并找到包含该ANSI编号的DataTable行,然后对其进行处理 由于DataTable.Select非常慢,我必须对列表中的每个项目都这样做,所以我尝试了更快的替代方案。请记住,DataTable对象没有数据库。所以我不能利用任何SQL功能或类似的功能 我认为最快的方法可能是创建一个带有KeyValuePair a:Ansi

在我正在编写的一个应用程序中,我有两组可能很大的数据需要相互映射。一个是从web服务返回的列表,另一个是DataTable。我需要获取列表中每个项目的ANSI或ISO编号,并找到包含该ANSI编号的DataTable行,然后对其进行处理

由于DataTable.Select非常慢,我必须对列表中的每个项目都这样做,所以我尝试了更快的替代方案。请记住,DataTable对象没有数据库。所以我不能利用任何SQL功能或类似的功能

我认为最快的方法可能是创建一个带有KeyValuePair a:Ansi编号或I:Iso编号的字典,并将其用作密钥。该值将是行的其余部分。创建该字典显然需要一点处理时间,但是我可以利用字典的极快搜索时间找到我需要的每一行,然后将这些行添加回表中。因此,在foreach循环中,对于列表,我将只具有O1的复杂性,使用字典,而不是On或任何DataTable

令我惊讶的是,这本词典的速度实在太慢了。我不明白为什么,直到我发现使用字符串而不是KeyValuePair可以显著提高性能。我说话快了几百倍。这到底是怎么可能的?以下是我的测试方法:

我生成一个模拟web服务输出的列表。我基于该列表创建了一个字典,其中的键为string或KeyValuePair,数据行为值。我对该列表进行foreach循环,在字典中搜索该列表中的每个项目,然后为返回的DataRow赋值。就这样

如果我使用KeyValuePair作为键来访问字典,则1000个项目需要几秒钟的时间;如果我将字典修改为仅使用字符串作为键,则10000个项目需要几毫秒的时间。仅供参考:我设计了这个测试,所以总是会有点击,所以所有的键都会被找到

下面是我正在测量时间的代码块:

foreach(ProductList.Products item in pList.Output.Products)
{
   //KeyValuePair<string, string> kv = new KeyValuePair<string, string>("A", item.Ansi);
   DataRow row = dict[item.Ansi];
   for (int i = 0; i < 10; i++)
   {
      row["Material"] = item.Material + "a"; //Do stuff just for debugging
   }
   hits++;
}
那么,如果我使用DictionaryKeyValuePair,DataRow而不是DictionaryString,DataRow,那么执行时间怎么可能突然变长数百倍呢?

KeyValuePair没有实现GetHashCode方法。这意味着唯一有意义地组织词典的方法已经不复存在,剩下的是效率低下的线性搜索

这并不奇怪,因为它不是KeyValuePair的设计目的——它是字典使用的内部结构,而不是键。不要求.NET对象是有用的键,从所有GetHashCode调用返回0是完全有效的

如果不想使用自己的结构,请使用Tuple。但我真的会为任何类型的持久性创建自己的结构,真的


作为旁注,DataTable.Select实际上非常快,它的设计目的是过滤输出数据。然而,它并不是为在一个循环中被调用数百次而设计的——开销占主导地位。当然,这假设您有适当的索引。在您的情况下,我认为每次调用Select时都会重新生成索引,这有点慢:

您可能会遇到大量与键值对的哈希冲突。您可以使用GetHashCode进行测试

下面的链接是元组,但我高度怀疑您对键值对也有同样的想法。我会标记为复制品,但你们很多人还有别的事情要做


在此情况下,Microsoft建议不要对密钥使用值类型。GetHashCode for从值类型继承而来。

这里的人过去不那么挑剔。我敢打赌,否决这个问题的人在按下不赞成按钮之前没有读过它。见鬼的人们,看在上帝的份上,不要再这样做了……不同的问题,但答案相同,请看Tuple也往往散列得很糟糕。事实上,创建自己的结构,并经常散列。只需返回最独特属性的散列就足够了。@Frisbee[需要引用]。当然,如果你知道什么样的偏差对你有用,有更好的散列方法,但是对于非结构化数据,Tuple工作得很好。@Frisbee Tuple的性能差是因为当与值类型一起使用时,它会在每次GetHashCode和Equals调用时将它们装箱。一些天才决定使用EqualityComparer.Default而不是EqualityComparer.Default。看@Lukazoid我不是在编造这个。元组散列效果很差。