【问题标题】:Segmented Hash Maps. Do more segments increase or decrease performance?分段哈希图。更多的细分会提高还是降低绩效?
【发布时间】:2017-12-19 21:48:57
【问题描述】:

我试图了解分段哈希映射的工作原理。我知道它们使哈希映射更加线程安全,但我不清楚将数据划分为段是否会增加每秒可以在给定哈希映射上执行的操作总数。

例如,如果我有一个包含 10,000 个元素的哈希映射并逐渐增加段数,我会看到程序的吞吐量和每秒操作数增加还是减少?

【问题讨论】:

  • 你问的是ConcurrentHashMapconcurrencyLevel参数吗?或者你的意思是“分段地图”的其他意思?
  • 嗨 Meriton,我说的是并发哈希映射。我已经阅读了并发哈希映射中的分段,但我不确定它们如何影响性能。由于每个段本质上是一个锁,肯定更多的段会减慢程序的速度,因为这意味着某些方法和操作必须等待?

标签: java concurrency hashmap


【解决方案1】:

concurrencyLevel 参数在现代实现中没有任何作用,它的存在只是为了保持 API 与早期版本的 JDK 的兼容性,或者如 Javadoc 所说:

此外,为了与此类的先前版本兼容,构造函数可以选择指定预期的concurrencyLevel 作为内部大小调整的附加提示。

如下implemented

public ConcurrentHashMap(int initialCapacity,
                         float loadFactor, int concurrencyLevel) {
    if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0)
        throw new IllegalArgumentException();
    if (initialCapacity < concurrencyLevel)   // Use at least as many bins
        initialCapacity = concurrencyLevel;   // as estimated threads
    long size = (long)(1.0 + (long)initialCapacity / loadFactor);
    int cap = (size >= (long)MAXIMUM_CAPACITY) ?
        MAXIMUM_CAPACITY : tableSizeFor((int)size);
    this.sizeCtl = cap;
}

也就是说,concurrencyLevel 仅在用户指定不切实际的低 initialCapacity 时覆盖 initialCapacity。就是这样。

此外,这只是设置地图的初始容量;实际容量会随着条目数量的增加而增加(由loadFactor 指示)。

总之,concurrencyLevel 除了最晦涩的用例(一个初始容量指定不明确的映射,包含的条目比访问它的线程少,而且由于所有线程花费大部分时间而引起激烈竞争)与该地图进行交互)。

你还问过:

由于每个段本质上是一个锁,肯定更多的段会减慢程序的速度,因为这意味着某些方法和操作必须等待?

要获取或放置一个值,线程只会锁定包含它的段。也就是说,将映射划分为更多的段不会导致每次操作都获取或释放更多的锁,但会降低锁争用的概率,因为每个段的条目更少。

另外,值得注意的是,ConcurrentHashMap 中的许多方法都是免等待的。例如,下面是获取值的方法:

public V get(Object key) {
    Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;
    int h = spread(key.hashCode());
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (e = tabAt(tab, (n - 1) & h)) != null) {
        if ((eh = e.hash) == h) {
            if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                return e.val;
        }
        else if (eh < 0)
            return (p = e.find(h, key)) != null ? p.val : null;
        while ((e = e.next) != null) {
            if (e.hash == h &&
                ((ek = e.key) == key || (ek != null && key.equals(ek))))
                return e.val;
        }
    }
    return null;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    • 2012-03-27
    • 1970-01-01
    • 2020-07-08
    • 2010-11-16
    • 2010-09-14
    • 1970-01-01
    相关资源
    最近更新 更多