C#字典 – 如何解决项目数限制?

我正在使用字典,我需要存储近13 000 000个密钥。 不幸的是,在添加了11 950 000个密钥后,我得到了一个例外“系统内存不足”。 有这个问题的解决方案吗? 我将需要我的程序在比以前更少的可用计算机上运行。

我需要那么多密钥,因为我需要存储对 – 序列名称和序列长度,它用于解决生物信息学相关问题。

任何帮助将不胜感激。

购买更多内存,安装64位版本的操作系统并重新编译为64位。 不,我不是在开玩笑。 如果你想要这么多物品……在ram ……然后称它为“特征”。 如果新的Android可以需要16GB的内存来编译…

我忘记了……你可以从阅读C#数组的对象开始,非常大,寻找更好的方法

你知道有多少是1300万个物体吗?

为了进行比较,32位Windows应用程序可以访问少于2 GB的地址空间。 所以它是20亿字节(给予或接受)…… 20亿/ 1300万=大约150字节/对象的东西。 现在,如果我们考虑参考类型占用多少……吃150个字节非常容易。

我会添加一些东西:我看了我的Magic 8-Ball ,它告诉我: 告诉我们你的代码 。 如果您没有告诉我们您使用的钥匙和价值,我们应该如何帮助您? 你在使用什么, classstruct或“原始”类型? 告诉我们你的TKeyTValue的“大小”。 可悲的是,昨天我们的结晶球破了:-)

C#不是一种旨在解决重型科学计算问题的语言。 绝对有可能使用C#来构建满足您需求的工具,但像Dictionary这样的现成部件旨在解决更常见的业务问题,例如将邮政编码映射到城市等等。

您将不得不使用某种外部存储。 我的建议是购买数据库并用它来存储你的数据。 然后使用DataSet或类似技术将部分数据加载到内存中,对其进行操作,然后将更多数据从数据库中倒入DataSet,依此类推。

好吧,我几乎完全一样的问题。

我想从数据库中将大约1250万[string,int] s加载到一个字典中(对于上面所有不明白原因的编程“众神”,答案是当你使用150时它会非常快) GB数据库,如果可以缓存内存中一个密钥表的一部分)。

它令人烦恼地在几乎相同的地方抛出一个内存不足 – 即使这个过程只消耗了大约1.3 GB的内存(在db读取方法明智地改为内存后减少到大约800 MB内存)不要尝试一次完成所有操作) – 尽管在I7上运行8 GB内存。

解决方案实际上非常简单 – 在解决方案资源管理器的Visual Studio(2010)中右键单击项目并选择属性。 在Build选项卡中,将Platform Target设置为x64并重建。

它会在几秒钟内完成对字典的加载,并且字典性能非常好。

简单的解决方案就是使用简单的DB。 在这种情况下最明显的解决方案是,IMHO使用SQLite .NET ,快速,简单且内存占用少。

我认为您需要一种新的处理方法。

我必须假设您从文件或数据库中获取数据,无论哪种方式都应该保留。

除了增加系统内存之外,你无法实际增加对Dictionary中存储的值数量的限制,但无论如何,它是处理如此大量数据的极其低效的方法。

您应该重新考虑您的算法,以便您可以在更易于管理的部分处理数据。 它意味着分阶段处理它,直到你得到你的结果。 这可能意味着许多通过数据的hundreeds,但这是唯一的方法。

我还建议您考虑使用generics来帮助加速重复处理并减少内存使用量。

请记住,系统性能和对外部存储数据(无论是外部磁盘存储或数据库)的访问之间仍然存在平衡行为。

这不是Dictionary对象的问题,而是服务器中的可用内存。 我已经做了一些调查来了解字典对象的失败,但它从未失败过。 以下是供您参考的代码

  private static void TestDictionaryLimit() { int intCnt = 0; Dictionary dItems = new Dictionary(); Console.WriteLine("Total number of iterations = {0}", long.MaxValue); Console.WriteLine("...."); for (long lngCnt = 0; lngCnt < long.MaxValue; lngCnt++) { if (lngCnt < 11950020) dItems.Add(lngCnt, lngCnt.ToString()); else break; if ((lngCnt % 100000).Equals(0)) Console.Write(intCnt++); } Console.WriteLine("Completed.."); Console.WriteLine("{0} number of items in dictionary", dItems.Count); } 

上面的代码执行正常,并且存储的内容超过了您提到的计数。

真的1300万件物品相当多。 如果13000000分配的课程是一个非常深的垃圾收集器胃!

此外,如果您找到使用默认.NET字典的方法,性能将非常糟糕,密钥太多,密钥数量接近31位散列可以使用的值的数量,在您使用的任何系统中性能都会很糟糕当然,记忆会太多了!

如果您需要的数据结构可以使用比哈希表更多的内存,则可能需要将自定义哈希表与自定义二进制树数据结构混合使用。 是的,可以编写自己的两个组合。

对于这个如此奇怪和具体的问题,您无法依赖.net哈希表。

考虑到树的查找复杂度为O(log n),而建筑复杂度为O(n * log n),当然,构建它会太长。 然后,您应该构建二进制树的哈希表(或反之亦然),这将允许您使用消耗更少内存的两个数据结构。

然后,考虑在32位模式下编译它,而不是在64位模式下编译:64位模式使用更多内存用于指针。 与此相反,我认为32位地址空间可能不足以解决您的问题。 我没有遇到过可以耗尽32位地址空间的问题!

如果键和值都是简单的值类型,我建议您在C dll中编写数据结构并通过C#使用它。

您可以尝试编写词典字典。 假设您可以将数据拆分为26个字典之间的500000个项目块,但占用的内存将非常大,不要认为您的系统会处理它。

 public class MySuperDictionary { private readonly Dictionary[] dictionaries; public MySuperDictionary() { this.dictionaries = new Dictionary[373]; // must be a prime number. for (int i = 0; i < dictionaries.Length; ++i) dictionaries[i] = new Dicionary(13000000 / dictionaries.Length); } public void Add(KEY key, VALUE value) { int bucket = (GetSecondaryHashCode(key) & 0x7FFFFFFF) % dictionaries.Length; dictionaries[bucket].Add(key, value); } public bool Remove(KEY key) { int bucket = (GetSecondaryHashCode(key) & 0x7FFFFFFF) % dictionaries.Length; return dictionaries[bucket].Remove(key); } public bool TryGetValue(KEY key, out VALUE result) { int bucket = (GetSecondaryHashCode(key) & 0x7FFFFFFF) % dictionaries.Length; return dictionaries[bucket].TryGetValue(key, out result); } public static int GetSecondaryHashCode(KEY key) { here you should return an hash code for key possibly using a different hashing algorithm than the algorithm you use in inner dictionaries } } 

使用那么多密钥,您应该使用数据库或类似memcache的东西,同时在存储中交换缓存块。 我怀疑你是否需要同时使用所有项目,如果你这样做,那么它就无法在内存很少的低功耗机器上运行。