持有百万件物品的最佳系列?

时间:2010-09-03 12:37:01

标签: .net performance collections

我想问一个有兴趣(对我而言)的问题。

如果集合包含大量项目(超过100万),那么按标准性能最佳的集合是什么。

例如,我创建了简单的List(10000000)集合,并尝试添加大约500000个不同的项目。运行后10秒内将首先添加30000件物品,但收集后将在运行后1分钟内仅包含60000件物品,在5分钟内将包含150000件物品。

据我所知,通过添加新项目(因为每个项目在“类似的相等”时间段内创建),存储器使用中存在非线性依赖性。但我可以犯错误。

编辑: 你是对的,没有样品就不够清楚。 我试图填充树作为连接列表。 您可以在下面找到示例代码。

public class Matrix
{
    public int Id { get; private set; }
    public byte[,] Items { get; private set; }
    public int ParentId { get; private set; }
    public int Lvl { get; private set; }
    public int HorizontalCounts
    {
        get { return 3; }
    }

    public int VerticalCounts
    {
        get { return 3; }
    }

    public Matrix(int id) : this(id, null, 0, 1)
    {
    }

    public Matrix(int id, byte[,] items, int parentId, int lvl)
    {
        Id = id;
        Items = (items ?? (new byte[HorizontalCounts, VerticalCounts]));
        ParentId = parentId;
        Lvl = lvl;
    }

    public bool IsEmpty(int hCounter, int vCounter)
    {
        return (Items[hCounter, vCounter] == 0);
    }

    public Matrix CreateChild(int id)
    {
        return (new Matrix(id, (byte[,])Items.Clone(), Id, (Lvl + 1)));
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        Matrix node = new Matrix(1);
        const int capacity = 10000000;
        List<Matrix> tree = new List<Matrix>(capacity) { node };

        FillTree(ref tree, ref node);

        int l1 = tree.Where(n => (n.Lvl == 1)).Count();
        int l2 = tree.Where(n => (n.Lvl == 2)).Count();
        int l3 = tree.Where(n => (n.Lvl == 3)).Count();
        int l4 = tree.Where(n => (n.Lvl == 4)).Count();
        int l5 = tree.Where(n => (n.Lvl == 5)).Count();
    }

    private static void FillTree(ref List<Matrix> tree, ref Matrix node)
    {
        for (int hCounter = 0; hCounter < node.HorizontalCounts; hCounter++)
        {
            for (int vCounter = 0; vCounter < node.VerticalCounts; vCounter++)
            {
                if (!node.IsEmpty(hCounter, vCounter))
                {
                    continue;
                }

                int childId = (tree.Select(n => n.Id).Max() + 1);
                Matrix childNode = node.CreateChild(childId);
                childNode.Items[hCounter, vCounter] = 1;

                tree.Add(childNode);

                FillTree(ref tree, ref childNode);
            }
        }
    }
}

最新版:我很抱歉,问题不在于需要收集的物品数量。性能问题在这一行:int childId =(tree.Select(n =&gt; n.Id).Max()+ 1);非常感谢您的回答和评论。

5 个答案:

答案 0 :(得分:3)

这个答案取决于它。你打算做很多没有排序的插页吗?链接列表
你打算做很多查找吗? HashMap中/字典
你是否只想拥有一组无序的东西?列表和/或数组
你不想要重复吗?设置
你不想要重复,但想要快速查找? HashSet的
您是否有按键排序的有序列表? TreeMap

答案 1 :(得分:2)

如果您想添加一百万个项目,请按以下方式创建:

var myList = new List<MyItem>(1500000);

存储150万个引用(或小结构)并不昂贵,让List的自适应增长算法分配空间将是昂贵的。

答案 2 :(得分:1)

除非数组要创建一次并且在应用程序的生命周期中存在,否则我倾向于建议某种类型的嵌套数组,其中如果每个数组包含任何双重数组,则每个数组的大小保持在8000字节以下精度浮点数,如果不是,则为85,000字节。大小的对象放在大对象堆上。与普通堆不同,普通堆可以有效地处理许多对象的创建和放弃,大型对象堆在.net 2.0-3.5下处理得很差,在4.0以下只能稍微好一些。

如果您不进行插入或删除,我建议最简单的方法是使用1024个1024个元素的数组。通过索引访问元素可以简单地将索引右移10,使用结果选择数组,然后使用底部的10位来查找数组中的项。

如果需要插入和删除,我建议使用锯齿状数组和某种数据结构来跟踪每个子数组的逻辑长度,并帮助将索引转换为数组位置。这样做可以避免在执行插入或删除时复制大量数据,但代价是更昂贵的下载操作。

答案 3 :(得分:0)

如果您事先知道确切的数量,那么您需要一个数组。如果你可以分配一次,然后简单地填充,那么一个简单的数组是完美的。没有浪费的内存,最快的填充,最快的删除。

答案 4 :(得分:0)

当您处理数百万(或更多)项目时,最好使用数组。即使您通过使阵列大于绝对必要而浪费了几千个插槽,所以获得的时间效率可能会弥补空间效率的损失。

当然,如果您处理的数据太大而无法完全存储在内存中,建议使用基于磁盘的数据结构。