我想分别加入两个列表的项目。
这是我的代码:
1.
List<String> pairs = list1.stream()
.parallel()
.flatMap(item1 -> list2.stream()
.parallel()
.map(item2 -> item1 + " " + item2))
.collect(Collectors.toList());
当我尝试类似的方法时,上面的方法是最快的..但我觉得这个方法不是并行的。 (因为结果的顺序总是一样的..!)
有没有更快的方法?最终结果列表的顺序无关紧要。
谢谢!
========================================
我尝试了另外两种方法
2.
List<String> pairs = new ArrayList<>();
for(String item1 : list1)
for(String item2 : list2)
pairs.add(item1 + " " + item2);
pool.submit(() -> {
List<String> pairs = list1.stream()
.parallel()
.flatMap(item1 -> list2.stream()
.parallel()
.map(item2 -> item1 + " " + item2))
.collect(Collectors.toList());
}).get();
答案 0 :(得分:1)
获取顺序流的问题在 flatMap 中。
这是关于 efficiently splittable
streams 的文章。
有几种方法可以分别组合两个或多个流。其中一种方法是使用 Guava Streams:
Streams
.zip(list1.stream(), list2.stream(), (item1, item2) -> item1 + ":" + item2)
请注意,此 Stream 也不是 efficiently splittable
。所以它会损害并行性能。您可以在此处找到更多方法:
答案 1 :(得分:0)
但是我感觉这个方法不是并行的。 (因为结果的顺序总是一样的..!)
你这里的推理是错误的。 toList()
可以在并行处理后按顺序返回项目。来自the docs:
如果流具有遇到顺序,但用户并不特别关心该遇到顺序,则使用 unordered() 显式取消流的排序可能会提高某些有状态或终端操作的并行性能。然而,大多数流管道,例如上面的“块权重总和”示例,即使在排序约束下仍然有效地并行化。
有关其工作原理的更多详细信息,我们可以查看 Collectors.toList 的实现:
public static <T>
Collector<T, ?, List<T>> toList() {
return new CollectorImpl<>(ArrayList::new, List::add,
(left, right) -> { left.addAll(right); return left; },
CH_ID);
}
处理流的每个线程创建一个单独的ArrayList
,并用add
按顺序将处理过的元素添加到列表中。稍后这些单独的列表使用 addAll
合并。由于每个线程处理一个有序批次的项目,而合并过程保留了批次的顺序,因此保留了整体顺序。