我有一个Id映射缓存占用了太多内存。它用于存放一个对象的3种不同类型的Id的组合,并且从表中读取它们的映射,并缓存在6个不同的字典中,以便从任何1 Id类型快速查找/转换到另一个(性能是对我的申请很重要。)
我想将其重写为内存占用较少的内容,因此我确实实现了Id的整合列表,并使用linq / lambda表达式来提取我想要的值。它现在看起来像这样。
public struct IdMappings
{
public int Id1;
public int Id2;
public int Id3;
}
//new cache
private static List<IdMappings> AllIdMappings = null;
//current cache implementation
private static Dictionary<int, int> Id1ToId2 = null;
private static Dictionary<int, int> Id1ToId3 = null;
//etc.
public static void FillCache(DataSet data)
{
foreach (DataRow r in data.Tables[0].Rows)
{
//fill list and/or dictionaries with id's
}
}
示例查找将是:
public static int GetId2FromId1(int id1)
{
return AllIdMappings.FirstOrDefault(m => m.Id1 == id1).Id2;
//or
return Id1ToId2[id1];
}
这就是我在减少内存使用方面所需要的,但是查找的性能因此受到影响,所以我看到了如何实现不同的东西。有没有办法做多索引键,或多键查找比迭代列表相对快?
答案 0 :(得分:1)
是的,对列表进行排序并使用二进制搜索(List&lt;&gt;已在方法Find中为您实现此功能) 然后在O(logn)中完成维护排序列表和查找。
答案 1 :(得分:1)
一个潜在的性能改进可能是使用Hashset<IdMappings>
而不是List<IdMappings>
,但这主要有助于直接查找,而不是FirstOrDefault
,或多或少,按顺序迭代列表。
如果您的查询全部来自ID1 - &gt; ID2和ID3方向,您可以使用Dictionary<int, Tuple<int, int>>
作为键,这将消除当前词典中ID1的额外值。
无论如何,根据定义,缓存是查找速度的内存交易,所以我认为你不能大幅提高内存消耗。
答案 2 :(得分:1)
如果添加这三个词典:
private static Dictionary<int, IdMappings> Id1Lookup = null;
private static Dictionary<int, IdMappings> Id2Lookup = null;
private static Dictionary<int, IdMappings> Id3Lookup = null;
如果字典值是相同的引用,它应该使用最少的内存,但保留与原始实现相同的查找速度。
如果我正在考虑这个问题,那么这应该使用6个字典解决方案的一半内存,但是使用List<IdMappings>
类型解决方案的两倍。
正如@SWeko指出的那样,IdMappings
需要是class
而不是struct
才能确保使用引用指针而不是副本。
答案 3 :(得分:1)
可能你最好的办法是创建一个映射结构:
struct Mapping: IComparable<Mapping>
{
private readonly int FromId;
private readonly int ToId;
public Mapping(int fid, int tid);
// implement the IComparable.Compare method to compare FromId
}
然后,为每个索引创建一个List<Mapping>
,并对列表进行排序。然后,您可以使用List.Find
查找所需的项目。