高效的IP地址列表

时间:2013-07-02 20:07:48

标签: c# .net data-structures hashset

使用IP4地址,显然可以32位存储。 我需要跟踪一个ip列表,这可能是一个相当长的列表,所以我希望尽可能保持紧密。我还需要快速搜索列表,以便检查是否已经加载了IP。

我目前正在研究:将IP转换为UInt32,然后将列表存储在HashSet中。

我觉得可能有更好的方法吗?

update:Hashsets当然会生成哈希值,这些哈希值大于uint的4个字节。因此,为了真正优化这一点,特别是对于IP4地址,需要一个针对4字节优化的类似结构

1 个答案:

答案 0 :(得分:2)

如果列表是相对静态的(即不经常更改),那么数组或List<uint>将是一种非常简单的存储方式。它为您提供了BinarySearch的O(log n)查找,这可能足够快,除非您每秒进行数千次查找。但是,在列表中插入新项是O(n)操作。如果你不得不做很多插入,那就不行了。

HashSet<uint>运行良好,查找和插入速度更快。但它会花费你。 HashSet<uint>占用的内存大约是List<uint>的3倍。

使用3X内存的理由:

下面的程序会分配一个List<uint>,其中包含89,478,457项,这些项目曾是可以创建的最大HashSet项。 (通过.NET 4.0。)然后使用唯一值填充该列表,并从列表中创建HashSet<uint>

程序通过调用GC.GetTotalMemory(true)计算总分配内存,这会强制进行垃圾回收。然后,它计算列表和哈希集所需的内存量。

使用.NET 4.5,Visual Studio 2012运行测试。在没有附加调试器的情况下以发布模式运行。

我的输出:

Max size = 89,478,457
Starting memory = 53,240
89,000,000
After list populated = 357,967,136
89,478,457 items in the HashSet
After HashSet populated = 1,789,622,704
List occupies 357,913,896
HashSet occupies 1,431,655,568
HashSet occupies 4.00 times the memory of List
Press Enter:

所以我错了...... uint是4倍。它是ulong的3.5倍。

    private void DoStuff()
    {
        int maxSize = 89478457;
            //89000000;
        Console.WriteLine("Max size = {0:N0}", maxSize);

        var startMem = GC.GetTotalMemory(true);
        Console.WriteLine("Starting memory = {0:N0}", startMem);

        // Initialize a List<long> to hold maxSize items
        var l = new List<uint>(maxSize);

        // now add items to the list
        for (uint i = 0; i < maxSize; i++)
        {
            if ((i % 1000000) == 0)
            {
                Console.Write("\r{0:N0}", i);
            }
            l.Add(i);
        }
        Console.WriteLine();

        var memAfterListAlloc = GC.GetTotalMemory(true);
        Console.WriteLine("After list populated = {0:N0}", memAfterListAlloc);

        // Construct a HashSet from that list
        var h = new HashSet<uint>(l);

        Console.WriteLine("{0:N0} items in the HashSet", h.Count);

        var memAfterHashAlloc = GC.GetTotalMemory(true);
        Console.WriteLine("After HashSet populated = {0:N0}", memAfterHashAlloc);

        var listMem = memAfterListAlloc - startMem;
        var hashMem = memAfterHashAlloc - memAfterListAlloc;

        Console.WriteLine("List occupies {0:N0}", listMem);
        Console.WriteLine("HashSet occupies {0:N0}", hashMem);

        Console.WriteLine("HashSet occupies {0:N2} times the memory of List", (double)hashMem / listMem);

        GC.KeepAlive(l);
        GC.KeepAlive(h);

        Console.Write("Press Enter:");
        Console.ReadLine();
    }