Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/cmake/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Data structures 是否有任何哈希表(内存中、非分布式)使用一致哈希?_Data Structures_Hashtable_Consistent Hashing - Fatal编程技术网

Data structures 是否有任何哈希表(内存中、非分布式)使用一致哈希?

Data structures 是否有任何哈希表(内存中、非分布式)使用一致哈希?,data-structures,hashtable,consistent-hashing,Data Structures,Hashtable,Consistent Hashing,我不是说分布式的键/值系统,比如通常与memcached一起使用的系统,它使用一致的散列使添加/删除节点成为一个相对便宜的过程 我说的是标准内存哈希表,比如python的dict或perl的哈希表 通过降低调整哈希表大小的成本,使用一致性哈希的好处似乎也适用于这些标准数据结构。实时系统(和其他对延迟敏感的系统)将受益于/需要为低成本增长而优化的哈希表,即使总体吞吐量略有下降 维基百科暗指“增量调整尺寸”,但基本上谈论的是热/冷替换方法来调整尺寸;另外还有一篇关于“可扩展散列”的文章,它使用tri

我不是说分布式的键/值系统,比如通常与memcached一起使用的系统,它使用一致的散列使添加/删除节点成为一个相对便宜的过程

我说的是标准内存哈希表,比如python的dict或perl的哈希表

通过降低调整哈希表大小的成本,使用一致性哈希的好处似乎也适用于这些标准数据结构。实时系统(和其他对延迟敏感的系统)将受益于/需要为低成本增长而优化的哈希表,即使总体吞吐量略有下降

维基百科暗指“增量调整尺寸”,但基本上谈论的是热/冷替换方法来调整尺寸;另外还有一篇关于“可扩展散列”的文章,它使用trie进行bucket查找以实现廉价的重新散列

如果有人听说过使用一致散列来降低增长成本的核心单节点散列表,那就奇怪了。或者使用其他方法(如上面列出的两个维基百科位)更好地满足这一要求

或者。。。我的整个问题都被误导了吗?内存分页的考虑是否使复杂性变得不值得?也就是说,一致性哈希的额外间接方式只允许您重新缓存总密钥的一小部分,但这可能并不重要,因为您可能必须从每个现有页面读取,因此内存延迟是您的主要因素,与内存访问成本相比,是否重新缓存部分或全部密钥并不重要。。。。但另一方面,使用一致散列,所有密钥重新映射都具有相同的目标页,因此,与密钥重新映射到任何现有页相比,内存波动会更少


编辑:添加了“data structures”标签,澄清了最后一句,将“page”改为“bucket”。

我在野外还没有听说过这一点,但是如果您选择正确的一致性哈希实现,这可能是一个好主意。具体来说,由Google等撰写。首先我将讨论为什么要跳转,然后我将讨论它如何在本地数据结构中有用

跳转一致散列 跳转一致性哈希(我将缩短为跳转)非常适合这个空间,原因如下。跳转假设节点不会发生故障,这对于本地数据结构非常有用,因为它们不会发生故障!这允许跳转仅仅是一个到一系列数字的映射
[0,numBuckets)
,只需要2-4字节的空间

此外,该实现简单而快速。如果我们删除参考实现的浮点除法,并用一半的整数除法替换它们,则速度会更快。(顺便说一下,我们可以这样做。)

所有这些都可以用于对

ConcurrentHashMap 但首先,Java是在一个高层次上

Java的ConcurrentHashMap由多个bucket参数化。该切分因子在映射的整个生命周期中都是恒定的。每个bucket本身就是一个具有自己锁的哈希映射

将密钥-值对插入到映射中时,密钥将散列到其中一个存储桶中。该密钥的锁将被获取,并且在释放锁之前,该项将被插入到存储桶的散列映射中。在插入存储桶
x
时,另一个线程可以同时插入存储桶
y
,但它将等待锁定如果插入bucket
x
。因此Java的ConcurrentHashMap具有n路并发性,其中n是构造函数的bucket参数

就像任何散列映射一样,ConcurrentHashMap中的一个bucket可能会被填满,需要增长。就像常规散列映射一样,它通过将其大小加倍并将bucket中的所有内容重新置回其更大的自我来实现这一点。除了“其更大的自我”只是bucket的“自我”。如果bucket是一个热点,并且获得的密钥超过其公平份额,则与其他存储桶相比,存储桶的增长将不成比例。每次存储桶的增长都需要越来越长的时间来重新存储到自身中。这最后一点不仅是热点的问题,而且是当哈希表plain old获得更多键时的问题

想象一下,如果我们可以随着密钥数量的增加而增加存储桶的数量,那么我们就可以抑制每个存储桶的增长量

输入一致散列,这允许我们添加更多存储桶

ConcurrentHashMap采用2:一致哈希样式 我们可以通过两个简单的步骤让ConcurrentHashMap增加存储桶的数量

首先,将映射到每个bucket的函数替换为jump-consistent散列函数。到目前为止,所有操作都应该是一样的

当一个桶被填满时,第二次拆分一个新桶;同时也要扩大已填满的桶。实际上,只有当已填满的桶成为容量最大的桶时,才拆分一个新桶。这可以在不迭代桶的情况下进行计算

使用一致的散列,拆分只会将密钥定向到新的存储桶中,而不会向后定向到任何旧的存储桶中

尾注
我相信这个方案会有所改进。也就是说,拆分一个存储桶需要进行一次完整的表扫描,才能将密钥移动到新的存储桶中。这当然不比普通的哈希映射差,而且可能更好,但它对ConcurrentHashMap实现不利,因为它可能不需要进行完整扫描。

我当然不这么认为快速浏览一下维基百科的描述就可以看出这一点。看起来您只需要保存重新哈希和一些表洗牌,但哈希函数无论如何都必须很快,移动条目很便宜(不像在分布式上下文中),而且调整大小的情况很少发生(有适当的增长策略),额外的间接寻址会降低所有查找的速度。但也许我遗漏了什么。delnan-是的,您只需节省重新哈希,而每次查找都需要另一次内存访问。但是如果