【问题标题】:Fast hash function for IPv4/6 addressesIPv4/6 地址的快速散列函数
【发布时间】:2014-03-30 18:33:50
【问题描述】:

我正在用 C 编写程序,它设计得很快

我想存储 IP 地址在数据流中出现的次数。例如,我将分析 100MB 的二进制文件,其中包含大约 2 000 000 个 IP 地址(但也许程序也会用于 x-GB 文件)。

我的想法是使用哈希表,所以我需要这些哈希函数:

20b_int indexToIPv4HashTable = hashIPv4(32b_int addr4);
20b_int indexToIPv6HashTable = hashIPv6(128b_int addr6);

我认为这个函数有时会发生冲突不是问题(我将使用单独的链接解决这个问题)。

  • 我应该使用哪些哈希函数?
  • 为这个问题使用哈希表是个好主意吗?

小数学:

  • 20b 索引 = 1 048 576 个元素(够了吗?
  • 32b 元素 = 4B 元素 = 4MB 表大小(这个大小可以吗,当程序将在 有电脑吗?)

注意: IP 地址可能已指定掩码。例如:IPv4/24 --> 现在只有 2^24 个不同的 IPv4 地址,而不是 2^32。 当掩码设置时,我应该使用不同的哈希表大小吗?

绝对优先考虑的是速度。

【问题讨论】:

  • addr[i] 和 addr[i+n] 之间是否存在相关性,其中 n 很小?在确定散列函数必须如何对位进行加扰时,这可能是一个关键因素。在 I7 中,很难在速度上击败 crc32 指令(或多项式乘法的组合),但重要的是整体性能。

标签: c hash hashtable ip-address hash-function


【解决方案1】:

顺便说一下,我假设您的意思是 4Gb,而不是 4Mb 的 32 位索引大小。此外,这假设每个条目只需要一个字节(最多 255 次命中)

在不知道地址分布的情况下很难知道哪个哈希值更好。如果它们或多或少随机分布在地址空间中(并且,是的,我知道大多数 IPv6 地址都没有分配),只需选择地址的几位并使用它。

例如,为 ipv4 选择五个均匀分布在地址中的 4 位区域,为 v6 选择中间某处的最低 16 位 + 4 位。

但如果您在现代 x86 上使用 crc32 指令几乎肯定会产生足够好的哈希值,而且速度很快。

#define HASH_MASK ((1<<20)-1)

static inline int hash32( unsigned int foo )
{
  return __builtin_ia32_crc32si( 0, foo ) & HASH_MASK;
}

static inline int hash128( const char *data )
{
  int res = 0, i;
  for( i=0; i<4; i++, data+=4 )
    res = __builtin_ia32_crc32si( res, *(int32_t *)data ); 
  return res & HASH_MASK;
}

请注意,这是高度不可移植的,它不仅只能在 x86 上工作,而且只能在某些 x86 机器上工作(如果您使用 gcc,它还需要 -msse4.2)。

注意:除非您每秒处理大量条目(我的意思是很多),否则哈希函数的速度不太重要。 哈希桶中数据的传播可能会影响事物,但即使是链表桶哈希表的简单非调整大小实现也将能够每秒处理至少数亿次点击,除非链接达到 100+长。 事实上,读取文件的硬盘驱动器的速度很可能是限制因素。

【讨论】:

    猜你喜欢
    • 2012-09-24
    • 1970-01-01
    • 2016-02-22
    • 1970-01-01
    • 2019-02-02
    • 1970-01-01
    • 2012-12-25
    • 2014-11-20
    • 1970-01-01
    相关资源
    最近更新 更多