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

时间:2011-10-24 14:03:26

标签: c# dictionary limit

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

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

任何帮助将不胜感激。

8 个答案:

答案 0 :(得分:9)

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

我忘记了......你可以先阅读C# array of objects, very large, looking for a better way

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

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

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

答案 1 :(得分:6)

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

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

答案 2 :(得分:5)

好吧,我的问题几乎完全相同。

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

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

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

它在几秒钟内完成了对字典的加载,并且字典表现非常好。

答案 3 :(得分:0)

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

答案 4 :(得分:0)

真的13000000件物品相当多。 如果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<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
    }
}

答案 5 :(得分:0)

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

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

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

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

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

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

答案 6 :(得分:0)

这不是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);
    }

上面的代码执行正确,并且存储的内容超过了你提到的数量。

答案 7 :(得分:-1)

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