将嵌套for循环替换为并行流-Java
我正在努力提高性能至关重要的程序的速度。目前它无法处理大型数据集。有许多嵌套for循环,因此我认为值得尝试并行流。我可以访问高性能群集,因此可能有许多内核可用。 我的方法如下:将嵌套for循环替换为并行流-Java,java,parallel-processing,java-8,java-stream,Java,Parallel Processing,Java 8,Java Stream,我正在努力提高性能至关重要的程序的速度。目前它无法处理大型数据集。有许多嵌套for循环,因此我认为值得尝试并行流。我可以访问高性能群集,因此可能有许多内核可用。 我的方法如下: public MinSpecSetFamily getMinDomSpecSets() { MinSpecSetFamily result = new MinSpecSetFamily(); ResourceType minRT = this.getFirstEssentialResour
public MinSpecSetFamily getMinDomSpecSets() {
MinSpecSetFamily result = new MinSpecSetFamily();
ResourceType minRT = this.getFirstEssentialResourceType();
if (minRT == null || minRT.noSpecies()) {
System.out.println("Problem in getMinDomSpecSets()");
}
for (Species spec : minRT.specList) {
SpecTree minTree = this.getMinimalConstSpecTreeRootedAt(spec);
ArrayList<SpecTreeNode> leafList = minTree.getLeaves();
for (SpecTreeNode leaf : leafList) {
ArrayList<Species> sp = leaf.getAncestors();
SpecSet tmpSet = new SpecSet(sp);
result.addSpecSet(tmpSet);
}
}
return result;
}
然而,我找不到显示如何处理每个for循环中的操作的示例,我对这应该如何工作一点也不自信。我真的很感激一些关于如何转换这个方法的帮助和解释,这样我也可以将解决方案转换成程序中的其他方法。
谢谢。这里有一种方法(希望我没有打字错误): 编辑:根据霍尔格的评论,你应该使用
收集
而不是减少
:
MinSpecSetFamily result =
minRT.specList
.parallelStream()
.flatMap(spec -> getMinimalConstSpecTreeRootedAt(spec).getLeaves().stream())
.map(leaf -> new SpecSet(leaf.getAncestors()))
.collect(MinSpecSetFamily::new,MinSpecSetFamily::addSpecSet,MinSpecSetFamily::add);
因此,您已经分析了软件,确定了热点,现在您对应该尝试优化的内容有了很好的想法?您的“将嵌套循环转换为并行流”基于实际数据,而不仅仅是猜测?是的,我尝试过使用分析,并确定此方法占用了大部分(99.7%)的处理时间。我不认为这是因为一个糟糕的方法,而是纯粹的计算量。谢谢你的帮助。因此,如果我创建一个新的构造函数,如:public MinSpecSetFamily(MinSpecSetFamily one,MinSpecSetFamily two),它返回一个新的对象来组合这两个对象,我将如何替换combiner?@SteveW
(f1,f2)->new(f1,f2)
。也许MinSpecSetFamily::new
也能起作用。但是,您不必返回新实例。将一个实例的数据添加到另一个实例并返回另一个实例可能会更有效。只是做了一些测试。在小型数据集上,并行流代码稍微慢一点。在问题数据集上,getLeaves方法被调用了数百万次。使用嵌套for循环,需要2m3sec才能获得5000万个getLeaves调用。使用parallelstream,在我的4核机器上进行同样的操作需要1米4秒。我不确定这是否是解决方案,但似乎确实有帮助。再次感谢您知道您可能在同一实例上同时调用fam.addSpecSet(set)
,然后在f1
和f2
中将该实例传递给new MinSpecSetFamily(f1,f2)
?这不是reduce
的目的。您肯定想使用collect
来代替。方法命名可能也没有帮助,因为,reduce
进行缩减,collect
进行可变缩减…
MinSpecSetFamily result =
minRT.specList
.parallelStream()
.flatMap(spec -> getMinimalConstSpecTreeRootedAt(spec).getLeaves().stream())
.map(leaf -> new SpecSet(leaf.getAncestors()))
.reduce(new MinSpecSetFamily (),
(fam,set)-> {
fam.addSpecSet(set);
return fam;
},
(f1, f2) -> new MinSpecSetFamily(f1, f2));
MinSpecSetFamily result =
minRT.specList
.parallelStream()
.flatMap(spec -> getMinimalConstSpecTreeRootedAt(spec).getLeaves().stream())
.map(leaf -> new SpecSet(leaf.getAncestors()))
.collect(MinSpecSetFamily::new,MinSpecSetFamily::addSpecSet,MinSpecSetFamily::add);