使用 IP4 地址,显然可以以 32 位存储。我需要跟踪一个 ip 列表,这可能是一个相当长的列表,因此希望尽可能保持紧凑。我还需要快速搜索列表,以检查其中是否已加载 IP。
我目前正在查看:将 IP 转换为 UInt32,然后将列表存储在 HashSet 中。
我在想可能有更好的方法吗?
更新:哈希集当然会生成哈希,它大于 uint 的 4 个字节。因此,要真正优化这一点,特别是针对 IP4 地址,需要一个针对 4 个字节进行优化的类似结构
使用 IP4 地址,显然可以以 32 位存储。我需要跟踪一个 ip 列表,这可能是一个相当长的列表,因此希望尽可能保持紧凑。我还需要快速搜索列表,以检查其中是否已加载 IP。
我目前正在查看:将 IP 转换为 UInt32,然后将列表存储在 HashSet 中。
我在想可能有更好的方法吗?
更新:哈希集当然会生成哈希,它大于 uint 的 4 个字节。因此,要真正优化这一点,特别是针对 IP4 地址,需要一个针对 4 个字节进行优化的类似结构
如果列表是相对静态的(即不经常更改),那么数组或 aList<uint>
将是一种非常简单的存储方式。它为您提供 O(log n) 查找BinarySearch
,这可能足够快,除非您每秒进行数千次查找。但是,在列表中插入一个新项目是一个 O(n) 操作。如果你必须做很多插入,这不是要走的路。
AHashSet<uint>
运行良好,查找和插入速度更快。但这会让你付出代价。AHashSet<uint>
将占用大约 3 倍于 a 的内存List<uint>
。
下面的程序分配了一个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:
所以我错了……它是 4 倍uint
。是 3.5 倍ulong
。
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();
}