使用parallelStream来使用Predicates过滤并发映射或列表是否更快?

时间:2015-03-24 20:23:49

标签: java collections concurrency java-8 predicate

我有多个FileMap个对象存储在List<FileMap>中,当前大约有500,000个对象。

我使用Predicates使用parallelStream过滤List。 我现在正在阅读文档,看到有一个名为Collectors.toConcurrentMap()的函数。我熟悉ConcurrentHashMap并且知道它更快,因为多个线程划分了地图。

将简单的ArrayList更改为toConcurrentMap,然后使用带有parallelStream的谓词更快地工作? 目前如果我在该List上使用parallelStream并使用serialStream,它的工作速度相同。

1 个答案:

答案 0 :(得分:1)

Map是key-value对的集合,其中键是唯一的。您拥有的数据不是地图,而是列表。有很多问题:

  1. 尝试将列表转换为地图需要提供键和值映射功能。
  2. 你最终会得到比原来更大的结构。
  3. 您必须确保键映射函数返回唯一值,因此无法进行并行化(您可以使用同步但会大大降低性能)。
  4. 地图的结构比列表(实际上是一个数组)更复杂,构建它需要更多的时间。
  5. ConcurrentMap具有额外的复杂性以确保线程安全 - 尽管它以更智能的方式完成,而不仅仅是使所有方法同步,它仍会影响性能。
  6. 迭代地图与数据的存储方式没什么关系 - 无论如何你都需要设置一个值。
  7. 过滤列表元素可以大量(并且容易)并行化。拥有n核心,其中n是列表的长度,您可以获得与log(n)一样好的性能 - 这当然是使用专门的并行算法并使用图形卡而不是CPU,虽然这些功能虽然不那么强大,却拥有数千个核心。

    我在一个包含1亿个整数的列表上运行了一些测试并按顺序处理大约700毫秒,使用并行流 - 大约350毫秒(我猜Java只使用了2个线程),同时尝试将列表转换为{{1几分钟后抛出内存错误。

    您提到使用ConcurrentMapstream()并未改变效果。我建议调查Java如何选择在并行流中使用多少线程(以及如何更改)。这也受到资源的影响 - 运行更多CPU消耗的线程比CPU中的内核数量会因上下文切换而降低性能。我建议只使用与你拥有的核心数量一样多的线程或者少一个 - 这样一个核心就可以用于所有其他操作系统工作。