从IEnumerable初始化Dictionary最高效的方法是什么?

时间:2017-02-27 02:13:15

标签: c# performance dictionary

我需要维护一个唯一键控的数据库对象的缓存(按整数)。查询提供了IEnumerable<MyEntity>MyEntity使用int主键)的实例和结果,我想尽快初始化Dictionary<int, MyEntity>的实例,因为这个查询可以返回几十万行。

Dictionary<int, MyEntity>初始化IEnumerable<MyEntity>实例的最佳效果是什么?

简而言之,我想知道是否有更高效的方法:

IEnumerable<MyEntity> entities = DoSomeQuery();

var cache = new Dictionary<int, MyEntity>();

foreach (var entity in entities)
    cache.Add(entity.Id, entity);

//or...

cache = entities.ToDictionary(e => e.Id);

当然,该查询具有最大的潜在性能影响,但重要的是,无论我在哪个用例中,我都要花几毫秒。

修改

值得注意的是,.ToDictionary<TKey, TElement> literally runs a foreach loop就像第一个例子一样,所以人们可以假设,如果不是稍微差一点,那将是完全相同的。也许这就是我的答案。

1 个答案:

答案 0 :(得分:5)

你的速度和你一样快。

如果您可以快速确定要添加的元素数量,那么将其作为容量传递给Dictionary构造函数将通过阻止内部调整大小操作(.NET Core版本的ToDictionary()这样做,其他版本没有。)

如果按键相对紧密,那么您可以从调整到范围而不是计数中受益。例如。如果您有Id {5, 6, 7, 9, 10, 11},那么将大小设置为7(如果缺少8那时您将拥有的值的数量)而不是6是有益的。(实际上,它在这里没有任何区别,因为效果只会在比这更大的集合中起作用)。但是效果相当小,所以如果你要浪费大量的内存就不值得做(例如,它绝对不值得将{8, 307}存储在一个300容量的字典中!这种好处来自增加频率在内部大小(因此内部散列减少)小于完成全部添加时的内容时,key将被散列到不会与其他元素冲突的内容。

如果它们紧密包装但您无法预测尺寸,那么将它们按顺序存储是有好处的,因为随着内部存储的增长,通常会出现字典希望存储某些内容的情况。未使用的简化哈希码。虽然好处将小于内存中排序的成本(并且无论如何都需要明确地或在OrderBy操作中找到元素的数量),所以只有获得这种排序的方法才有用为你做得便宜。 (例如,某些web服务要求给出某些类别的排序标准,因此您也可以将id作为标准。大多数情况下这不适用。)

这些点,特别是最后两点,虽然是微小的效果,但可能不会增加任何可衡量的效果。即使第一个小于获得计数的成本,如果它还没有在具有便宜的CountLength操作的来源中。

foreach本身也许可以通过替换索引(适用时)来改进,但有时也会更糟。它也往往在一些具体类型的源上做得更好(即foreach T[] foreach List<T> foreach IEnumerable<T> void readData() { int **arr,m; scanf("%d",&m); arr = (int **)malloc(sizeof(int)*m); for(int i=0;i<m;i++) { arr[i] = (int *)malloc(sizeof(int) * 2); } for(int i=0;i<m;i++) { printf("..%d ..\n",i); // if m = 20 then running only 12 times scanf("%d %d",&arr[i][0],&arr[i][1]); } } int main() { readData(); } {{1}} {{1}} )但这意味着在层之间公开实现细节并且很少值得,特别是因为许多集合类型没有任何好处。