nob*_*ody 3 java parallel-processing java-8 java-stream
使用spliterator()通过Iterable 创建的流时,我遇到了性能问题 .就像StreamSupport.stream(integerList.spliterator(), true).想要在正常的系列中证明这一点.请参阅下面的一些基准测试结果
问题:为什么从迭代创建的并行流比从ArrayList或IntStream创建的流慢得多?
从一个范围
public void testParallelFromIntRange() {
long start = System.nanoTime();
IntStream stream = IntStream.rangeClosed(1, Integer.MAX_VALUE).parallel();
System.out.println("Is Parallel: "+stream.isParallel());
stream.forEach(ParallelStreamSupportTest::calculate);
long end = System.nanoTime();
System.out.println("ParallelStream from range Takes : " + TimeUnit.MILLISECONDS.convert((end - start),
TimeUnit.NANOSECONDS) + " milli seconds");
}
Run Code Online (Sandbox Code Playgroud)
Is Parallel:true
范围内的ParallelStream Takes:490毫秒
来自Iterable
public void testParallelFromIterable() {
Set<Integer> integerList = ContiguousSet.create(Range.closed(1, Integer.MAX_VALUE), DiscreteDomain.integers());
long start = System.nanoTime();
Stream<Integer> stream = StreamSupport.stream(integerList.spliterator(), true);
System.out.println("Is Parallel: " + stream.isParallel());
stream.forEach(ParallelStreamSupportTest::calculate);
long end = System.nanoTime();
System.out.println("ParallelStream from Iterable Takes : " + TimeUnit.MILLISECONDS.convert((end - start),
TimeUnit.NANOSECONDS) + " milli seconds");
}
Run Code Online (Sandbox Code Playgroud)
Is Parallel:
来自Iterable Takes的真正ParallelStream:12517毫秒
而如此琐碎的计算方法.
public static Integer calculate(Integer input) {
return input + 2;
}
Run Code Online (Sandbox Code Playgroud)
Bri*_*etz 11
并非所有的分裂者都是平等的.分裂器的任务之一是将源分解为两部分,可以并行处理.一个好的分裂器会将源大致分成两半(并且能够以递归的方式继续这样做.)
现在,假设您正在编写一个仅由迭代器描述的源的分裂器.你能得到什么样的分解质量?基本上,您所能做的就是将源分为"第一"和"休息".那就差不多了.结果是一个非常"右重"的计算树.
从数据结构中获得的分裂器有更多可以使用; 它知道数据的布局,并且可以使用它来提供更好的分割,从而获得更好的并行性能.ArrayList的分裂器总是可以分成两半,并且保留每半数据中究竟有多少数据的知识.这非常好.来自平衡树的分裂器可以获得良好的分布(因为树的每一半都具有大约一半的元素),但是不如ArrayList分裂器那么好,因为它不知道确切的大小.LinkedList的分裂器和它一样糟糕; 它所能做的就是(首先,休息).从迭代器派生分裂器也是如此.
现在,一切都不一定丢失; 如果每个元素的工作量很高,你就可以克服坏分裂.但是如果你在每个元素上做了少量工作,那么你将受到分裂器分裂质量的限制.
您的基准测试有几个问题.
Stream<Integer>IntStream因为拳击开销无法比较. System.nanoTime而不是使用适当的基准测试工具.这是基于JMH的基准:
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.Range;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.OptionsBuilder;
public class Ranges {
final static int SIZE = 10_000_000;
@Benchmark
public long intStream() {
Stream<Integer> st = IntStream.rangeClosed(1, SIZE).boxed();
return st.parallel().mapToInt(x -> x).sum();
}
@Benchmark
public long contiguousSet() {
ContiguousSet<Integer> cs = ContiguousSet.create(Range.closed(1, SIZE), DiscreteDomain.integers());
Stream<Integer> st = cs.stream();
return st.parallel().mapToInt(x -> x).sum();
}
public static void main(String[] args) throws RunnerException {
new Runner(
new OptionsBuilder()
.include(".*Ranges.*")
.forks(1)
.warmupIterations(5)
.measurementIterations(5)
.build()
).run();
}
}
Run Code Online (Sandbox Code Playgroud)
并输出:
Benchmark Mode Samples Score Score error Units
b.Ranges.contiguousSet thrpt 5 13.540 0.924 ops/s
b.Ranges.intStream thrpt 5 27.047 5.119 ops/s
Run Code Online (Sandbox Code Playgroud)
IntStream.range因为ContiguousSetContiguousSet没有实现自己的Spliterator并且使用默认的,所以它的速度大约是两倍,这是完全合理的.Set
| 归档时间: |
|
| 查看次数: |
641 次 |
| 最近记录: |