我正在测试在Java中列表中搜索低值和高值的不同方法,并且我意识到使用stream()和parallelStream()方法的结果更慢且性能更低,而不仅仅是迭代列表。
这可能吗? 这怎么可能?这是我的代码:
迭代整个数组:
private HighLowTuple calculateIteratingWholeArray( List<Integer> arrayWithNumbers, int from, int to )
{
// long start = System.currentTimeMillis();
HighLowTuple result = new HighLowTuple( -1, Integer.MAX_VALUE );
for( int i = from; i < to; i++ )
{
int value = arrayWithNumbers.get( i );
if( value > result.high )
{
result.high = value;
}
if( value < result.low )
{
result.low = value;
}
}
// long end = System.currentTimeMillis();
// System.out.println( "duration internal calculateIteratingWholeArray from " + from +
// " to + " + to + " "
// + ( end - start ) + " ms" );
return result;
}
这里是使用java 8流的代码:
private HighLowTuple calculateUsingStreamParallel( List<Integer> arrayWithIntegers )
{
HighLowTuple result = new HighLowTuple( -1, Integer.MAX_VALUE );
Consumer<Integer> highlow = new Consumer<Integer>()
{
@Override
public void accept( Integer number )
{
if( result.high < number )
result.high = number;
if( result.low > number )
result.low = number;
}
};
arrayWithIntegers.stream().parallel().forEach( highlow );
return result;
}
答案 0 :(得分:8)
在开始考虑性能之前,您应该考虑正确性。您正在使用 parallel 流以及非线程安全的自定义有状态Consumer
:
if( result.high < number )
// if another thread updates ⟨high⟩ right at this point you might loose a value
result.high = number;
if( result.low > number )
// again, possible loss of values here
result.low = number;
此外,除非您已将变量HighLowTuple.high
和HighLowTuple.low
声明为volatile
,否则当您在没有同步的情况下使用多线程时,JVM的优化可能会导致更多的更新丢失。但是 if 你已声明它们volatile
你不应该对性能降低感到惊讶(虽然代码不正确)。
解决方案是首先了解API。你已经重新发明了这个轮子,因为已经有一种简洁的方法可以在Java 8中找到高低:
IntSummaryStatistics s = arrayWithIntegers.stream()
.parallel().mapToInt(Integer::intValue).summaryStatistics();
// if you still like your tuple class:
return new HighLowTuple(s.getMax(), s.getMin());
但是,当然,如果你有一组int
值,那么使用IntStream
代替它会更有效率,而不是绕道而去绕Collection
Integer
:
IntSummaryStatistics s = IntStream.of(array).parallel().summaryStatistics();