c#如何解决项目数量的限制
本文关键字:项目数 解决 何解决 | 更新日期: 2023-09-27 18:12:07
我正在使用字典,我需要在其中存储近13 000 000个键。不幸的是,在添加了1150000个键之后,我得到了一个异常"系统内存不足"。这个问题有解决办法吗?在未来,我需要我的程序在比我的计算机更弱的计算机上运行。
我需要这么多的键,因为我需要存储对-序列名称和序列长度,这是为了解决生物信息学相关问题。
任何帮助将不胜感激。
购买更多内存,安装64位版本的操作系统并重新编译为64位。不,我不是在开玩笑。如果你想要这么多东西…在ram中……然后称之为"特征"。如果新的Android需要16gb内存来编译…
我忘了…你可以从阅读c#对象数组开始,非常大,寻找一个更好的方法
你知道1300万个对象是多少吗?
做个比较,一个32位的Windows应用程序可以访问不到2gb的地址空间。所以它是20亿字节(左右)…20亿/1300万=大约150字节/对象。现在,如果我们考虑一个引用类型占用多少空间……150字节很容易被吃掉。
我要添加一些东西:我已经查看了我的Magic 8-Ball
,它告诉我:显示我们您的代码。如果您不告诉我们您使用的键和值是什么,我们该如何帮助您?你用的是什么,class
还是struct
还是"原始"类型?告诉我们你的TKey
和TValue
的"尺寸"。遗憾的是,我们的水晶球昨天破了:-)
c#并不是一种设计用来解决重型科学计算问题的语言。使用c#构建工具来做你想做的事情绝对是可能的,但是像Dictionary这样的现成部分是用来解决更常见的业务问题的,比如将邮政编码映射到城市和类似的事情。
你将不得不使用某种外部存储。我的建议是购买一个数据库并用它来存储数据。然后使用DataSet或一些类似的技术将数据的部分加载到内存中,对它们进行操作,然后将更多的数据从数据库中倒入DataSet,以此类推。
我也遇到过几乎完全相同的问题。
我想从数据库中加载大约1250万个[string, int]s到一个字典中(对于上面所有不明白为什么的编程"神"来说,答案是当你使用150gb的数据库时,如果你可以在内存中缓存一部分键表,那么它会快得多)。
它在几乎相同的地方抛出了一个令人恼火的内存不足异常-略低于1200万标记,尽管进程只消耗了大约1.3 GB的内存(在明智地改变db读取方法后减少到大约800 MB的内存)-尽管运行在具有8 GB内存的I7上。
解决方案实际上非常简单在Visual Studio(2010)的解决方案资源管理器中右键单击项目并选择属性。在Build选项卡中,将Platform Target设置为x64并重新构建。
它在几秒钟内将负载加载到Dictionary中,并且Dictionary的性能非常好。
简单的解决方案就是使用简单的DB。在这种情况下,最明显的解决方案是使用SQLite . net,快速,简单,内存占用少。
我认为你们需要一种新的处理方法。
我必须假设您从文件或数据库中获取数据,无论哪种方式,它都应该保存在那里。
除了增加系统内存之外,你没有办法增加字典中存储的值的数量限制,但无论如何,这是处理如此大量数据的一种极其低效的方法。
你应该重新考虑你的算法,以便你可以处理更易于管理的数据部分。这意味着要分阶段处理,直到你得到你的结果。这可能意味着要对数据进行数百次传递,但这是唯一的方法。
我还建议您考虑使用泛型来帮助加快这种重复处理并减少内存使用。
请记住,在系统性能和访问外部存储的数据(无论是外部磁盘存储还是数据库)之间仍然存在平衡行为。
这不是Dictionary对象的问题,而是服务器中的可用内存。我做了一些调查来了解字典对象的失败,但它从来没有失败过。下面是参考
的代码 private static void TestDictionaryLimit()
{
int intCnt = 0;
Dictionary<long, string> dItems = new Dictionary<long, string>();
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);
}
上面的代码执行正确,并且存储的计数数比您提到的要多。
13000000个条目真的很多。如果13000000个类都被分配,那是一个非常深踢进垃圾收集器胃里的动作!
如果你找到一种方法来使用默认的。net字典,性能将会非常糟糕,太多的键,键的数量接近31位哈希可以使用的值的数量,无论你使用什么系统,性能都会很糟糕,当然,内存也会太多!
如果你需要一个比哈希表使用更多内存的数据结构,你可能需要一个混合了自定义二叉树数据结构的自定义哈希表。是的,你可以写自己的组合。
你不能依靠。net哈希表来解决这个奇怪而特殊的问题。
考虑一棵树的查找复杂度为O(log n),而构建复杂度为O(n * log n),当然,构建它会太长。然后,您应该构建一个二叉树的哈希表(反之亦然),这将允许您使用两种数据结构,消耗更少的内存。
然后,考虑在32位模式下编译它,而不是在64位模式下:64位模式会为指针使用更多内存。同时,它有可能相反,32位地址空间可能不足以解决您的问题。它从来没有发生在我有一个问题,可以运行出32位地址空间!
如果键和值都是简单的值类型,我建议你在C dll中编写你的数据结构,并通过c#使用它。
你可以试着写一本字典的字典。比方说,你可以把数据分成50万项的块,放在26个字典中,但是占用的内存会非常非常大,不要认为你的系统会处理它。
public class MySuperDictionary
{
private readonly Dictionary<KEY, VALUE>[] dictionaries;
public MySuperDictionary()
{
this.dictionaries = new Dictionary<KEY, VALUE>[373]; // must be a prime number.
for (int i = 0; i < dictionaries.Length; ++i)
dictionaries[i] = new Dicionary<KEY, VALUE>(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之类的东西。我怀疑你一次需要所有的项目,如果你这样做,它不可能在一个低功率、小内存的机器上工作。