web-dev-qa-db-ja.com

高性能同時MultiMap Java / Scala

高性能な並行マルチマップを探しています。私はどこでも検索しましたが、ConcurrentHashMapと同じアプローチを使用するソリューションを見つけることができません(ハッシュ配列のセグメントのみをロックします)。

マルチマップは、頻繁に読み取られ、追加され、削除されます。

マルチマップキーは文字列であり、その値は任意です。

特定のキーのすべての値を見つけるにはO(1)が必要です、O(N)は削除しても問題ありませんが、O(logN)が推奨されます。

特定のキーの最後の値を削除すると、メモリがリークしないように、キーから値のコンテナが削除されることが重要です。

編集:ここに私が構築したソリューションがあります、ApacheV2で利用可能: Index(multimap)

59
Viktor Klang

ConcurrentHashMap [T、ConcurrentLinkedQueue [U]]をいくつかのNice Scalaに似たメソッド(たとえば、Iterableへの暗黙の変換または必要なもの、および更新メソッド)でラップしないのはなぜですか?

12
Rex Kerr

Googleコレクションを試しましたか?さまざまな Multimap 実装があります。

8
Jon Freedman

1つはakka がありますが、使用していません。

4
lisak

Mutable.MultiMapミックスインを拡張し、concurrent.Map [A​​、Set [B]]セルフタイプを持つ ConcurrentMultiMap mixinを作成しました。 O(n)スペースの複雑さ)を持つキーごとにロックしますが、特に書き込みが多すぎない場合は、時間の複雑さはかなり良好です。

3
nnythm

ctries を試してみてください。こちらが pdf です。

1
Shlomi

私はMap<Comparable, Set<Comparable>>マップでの挿入は同時に行われ、対応するセットでも行われますが、キーがマップから消費されると、削除する必要があり、2秒ごとに実行されるジョブが全体を消費していると考えてくださいSet<Comparable>特定のキーからですが、挿入は完全に同時に行われるため、ジョブが開始したときにほとんどの値がバッファリングされます。これが私の実装です。

注: GuavaのヘルパークラスMapsを使用して並行マップを作成します。また、このソリューションはJavaの同時実行をエミュレートリスト5.19でエミュレートします

import com.google.common.collect.MapMaker;
import com.google.common.collect.Sets;

import Java.util.Collection;
import Java.util.Set;
import Java.util.concurrent.ConcurrentMap;

/**
 * A general purpose Multimap implementation for delayed processing and concurrent insertion/deletes.
 *
 * @param <K> A comparable Key
 * @param <V> A comparable Value
 */
public class ConcurrentMultiMap<K extends Comparable, V extends Comparable>
{
  private final int size;
  private final ConcurrentMap<K, Set<V>> cache;
  private final ConcurrentMap<K, Object> locks;

  public ConcurrentMultiMap()
  {
    this(32, 2);
  }

  public ConcurrentMultiMap(final int concurrencyLevel)
  {
    this(concurrencyLevel, 2);
  }

  public ConcurrentMultiMap(final int concurrencyLevel, final int factor)
  {
    size=concurrencyLevel * factor;
    cache=new MapMaker().concurrencyLevel(concurrencyLevel).initialCapacity(concurrencyLevel).makeMap();
    locks=new MapMaker().concurrencyLevel(concurrencyLevel).initialCapacity(concurrencyLevel).weakKeys().weakValues().makeMap();
  }

  private Object getLock(final K key){
    final Object object=new Object();
    Object lock=locks.putIfAbsent(key, object);
    if(lock == null){
      lock=object;
    }
    return lock;
  }

  public void put(final K key, final V value)
  {
    synchronized(getLock(key)){
      Set<V> set=cache.get(key);
      if(set == null){
        set=Sets.newHashSetWithExpectedSize(size);
        cache.put(key, set);
      }
      set.add(value);
    }
  }

  public void putAll(final K key, final Collection<V> values)
  {
    synchronized(getLock(key)){
      Set<V> set=cache.get(key);
      if(set == null){
        set=Sets.newHashSetWithExpectedSize(size);
        cache.put(key, set);
      }
      set.addAll(values);
    }
  }

  public Set<V> remove(final K key)
  {
    synchronized(getLock(key)){
      return cache.remove(key);
    }
  }

  public Set<K> getKeySet()
  {
    return cache.keySet();
  }

  public int size()
  {
    return cache.size();
  }

}
1
Guido Medina

私はこのトピックについて少し遅れていますが、今日では、次のようにGuavaを使用できます。

Multimaps.newSetMultimap(new ConcurrentHashMap<>(), ConcurrentHashMap::newKeySet)
0
teo

Javalution を見てください。これは、リアルタイムなどを目的としたもので、もちろん高性能です。

0
khmarbaise

まだ議論には遅れていますが...

高性能の並行処理に関しては、ソリューションをコーディングする準備をする必要があります。同時使用で、ステートメントは悪魔が詳細にありますは完全な意味を持っています。完全に並行してロックフリーの構造を実装することが可能です。

開始ベースはNonBlocking Hashtable http://sourceforge.net/projects/high-scale-lib/ であり、キーごとの値の数と、書き込み時にコピーを追加/削除する頻度に依存します値のObject []またはセマフォ/スピンロックを使用した配列ベースのSet。

0
bestsss