2015-12-05 1 views
5

私は、JavaストリームAPIを介して行くことによって並列に一覧から地図を取り込もうとし、次のコードを持っている:マップが複数のスレッドを使用して移入された場合Java Streamの収集(Collectors.toMap)が並列化されているかどうかを確認するにはどうすればよいですか?

class NameId {...} 

public class TestStream 
{ 
    static public void main(String[] args) 
    { 
     List<NameId > niList = new ArrayList<>(); 
     niList.add(new NameId ("Alice", "123456")); 
     niList.add(new NameId ("Bob", "223456")); 
     niList.add(new NameId ("Carl", "323456")); 

     Stream<NameId> niStream = niList.parallelStream(); 
     Map<String, String> niMap = niStream.collect(Collectors.toMap(NameId::getName, NameId::getId)); 
    } 
} 

は、どのように私は知っている、すなわち中平行? Collectors.toMapの代わりにCollectors.toConcurrentMapを呼び出す必要がありますか?これは地図の人口を並列化するための合理的な方法ですか?具体的なマップが新しいniMapを裏付けしているかどうかを知るにはどうすればよいですか(たとえばHashMapですか)? Javadocから

+0

nはあなたのプロセッサが持つコアの数である:

注標準のストリームAPIを強化し、私のStreamExライブラリーは、同時、順次1のための並列ストリームと非同時コレクションのコレクションを使用していますtoMap()メソッドを追加していること並列ストリームで動作するようにn-1スレッドが作成されます。あなたのリストには3つの行がありますので、パフォーマンスが低下する可能性が最も高くなります。 –

+0

ストリームフレームワークは意図的に実装を非表示(並列または非表示)します。すべてが正しく行われていれば、教える方法はありません。 –

答えて

2

返さコレクターは、同時ではありません。並列ストリームパイプラインの場合、コンバイナ機能は、あるマップのキーを別のマップにマージすることによって動作します。これは高価な操作になります。検索結果をMapに挿入する必要がない場合は、toConcurrentMap(Function、Function)を使用すると、より良い並列パフォーマンスが得られる可能性があります。

したがって、toConcurrentMapは挿入を並列化するようです。

バッキングマップは、デフォルトでHashMapです。それはちょうどtoMapのバージョンを呼び出し、それはSupplier<M>をとり、HashMap::newを渡します。 (ソース:ソース)

2

複数のスレッドを使用して、つまり並列でマップが作成されているかどうかを確認するにはどうすればよいですか?

わかりにくいです。意外にもあなたのコードがに遅れている場合は、が複数のスレッドを使用しようとしている可能性があります。

Collectors.toMapではなく、Collectors.toConcurrentMapを呼び出す必要がありますか?

これは、パラレルをより効率的にするか、別の方法で配置するのに役立ちますが、それほど非効率的ではありません。

これは地図の母集団を並列化するための合理的な方法ですか?

新しいスレッドを開始するコストは、ここで行っているすべてのスレッドよりもはるかに高価であるため、スレッドを1つでも追加すると、スレッドの速度が大幅に低下することに注意してください。

具体的なマップが新しいniMap(たとえばHashMap)を裏付けているかどうかを知るにはどうすればよいですか?

ドキュメントには、わからないと書かれています。最後にtoMapをチェックしたときにHashMapが使用され、groupingByがLinkedHashMapを使用していましたが、特定のマップであるとは限りません。

+0

niMap.getClassはどのマップが使用されているかを教えてくれませんか? –

+1

@ Jean-FrançoisSavardはい、それはあなたがそれをどのように呼び出すかによって、Javaの更新と理論の間で異なる実装になる可能性があります。つまり、オブジェクトに空のマップを渡さない場合、またはそれがsingletonMap()である可能性があります。変更可能と見なすことさえできません。 –

+0

'groupingBy'がLinkedHashMapを使用するときは?私はこれを見たことがない。 –

1

シーケンシャルストリームの場合はtoConcurrentMap、パラレルストリームの場合はtoMapの両方を使用できます。違いは

  • toConcurrentMap()はあなたのストリームが来た場所がわからない場合は
  • toMap()が並列ストリーム

のためのより順次ストリームのために通常より速く、通常より速く順次ストリームよりも並列ストリームのです両方の場合でより速くしたい場合は、次のように書くことができます:

Map<String, String> niMap = niStream.collect(
    niStream.isParallel() ? 
     Collectors.toConcurrentMap(NameId::getName, NameId::getId) : 
     Collectors.toMap(NameId::getName, NameId::getId) 
); 

違いはtoConcurrentMap()CONCURRENTコレクタです。つまり、異なるスレッドから同時にデータを取り込むことができる同時データ構造(現在の実装ではConcurrentHashMap)が使用されています。シーケンシャルストリームの場合、不必要なオーバーヘッドが追加されますが、パラレルストリームの場合、toMap()のようにtoMap()の場合よりも高速です。すべてのパラレルスレッドに対して個別の非同期マップインスタンスが作成されると、これらのマップはマージされます。 。

Map<String, String> niMap = StreamEx.of(niStream) 
         .toMap(NameId::getName, NameId::getId); 
関連する問題