[英]How is the c#/.net 3.5 dictionary implemented?
我正在使用一个应用程序,该应用程序使用许多大型词典(最多 10^6 个元素),其大小事先未知(尽管在某些情况下我可以猜测)。 我想知道字典是如何实现的,即如果我不给出字典大小的初始估计,效果会有多糟糕。 它是否像 List 那样在内部使用(自增长)数组? 在这种情况下,让字典增长可能会在 LOH 上留下大量未引用的大型数组。
使用Reflector ,我发现以下内容: 字典将数据保存在结构数组中。 它会计算该数组中还剩下多少空位。 当您添加一个项目并且没有空的地方时,它会增加内部数组的大小(见下文)并将数据从旧数组复制到新数组。
因此,如果您知道会有很多条目,我建议您应该使用在其中设置初始大小的构造函数。
编辑:逻辑实际上非常有趣:有一个名为HashHelpers
的内部类来查找素数。 为了加快速度,它还在一个静态数组中存储了一些素数,从 3 到 7199369(有些丢失了;原因见下文)。 当您提供容量时,它会从数组中找到下一个素数(相同或更大的值),并将其用作初始容量。 如果你给它一个比它的数组更大的数字,它会开始手动检查。
因此,如果没有任何内容作为容量传递给字典,则起始容量为 3。
一旦超出容量,它将当前容量乘以 2,然后使用辅助类查找下一个更大的素数。 这就是为什么在数组中并不是每个素数都需要的原因,因为素数“靠得太近”并不是真正需要的。
所以如果我们不传递初始值,我们会得到(我检查了内部数组):
一旦我们传递了这个大小,下一步就落在内部数组之外,它将手动搜索更大的素数。 这会很慢。 您可以使用 7199369(数组中的最大值)进行初始化,或者考虑字典中的条目超过 500 万是否意味着您应该重新考虑您的设计。
MSDN说:“使用键检索值非常快,接近 O(1),因为 Dictionary 类是作为哈希表实现的。” 并进一步“通过重新分配内部阵列,根据需要自动增加容量”。
但是如果你给出一个初始估计,你会得到更少的重新分配。 如果您从一开始就拥有所有项目,则 LINQ 方法ToDictionary可能会很方便。
哈希表通常有一个叫做负载因子的东西,如果达到这个阈值,它会增加后备桶存储。 IIRC 默认值类似于 0.72。 如果你有完美的散列,这可以增加到 1.0。
此外,当哈希表需要更多桶时,必须重新哈希整个集合。
{
"Details":
{
"ApiKey": 50125
}
}
public Dictionary<string, string> Details{ get; set; }
foreach (KeyValuePair<string, string> dict in Details)
{
switch (dict.Key)
{
case nameof(settings.ApiKey):
int.TryParse(kv.Value, out int ApiKey);
settings.ApiKey=ApiKey;
break;
default:
break;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.