3 回答

TA貢獻(xiàn)1858條經(jīng)驗(yàn) 獲得超8個贊
LinkedList使用迭代器停止使用除列表中間的大量刪除之外的任何內(nèi)容。
停止手動編寫基準(zhǔn)測試代碼,使用JMH。
適當(dāng)?shù)幕鶞?zhǔn):
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
@OperationsPerInvocation(StreamVsVanilla.N)
public class StreamVsVanilla {
public static final int N = 10000;
static List<Integer> sourceList = new ArrayList<>();
static {
for (int i = 0; i < N; i++) {
sourceList.add(i);
}
}
@Benchmark
public List<Double> vanilla() {
List<Double> result = new ArrayList<>(sourceList.size() / 2 + 1);
for (Integer i : sourceList) {
if (i % 2 == 0){
result.add(Math.sqrt(i));
}
}
return result;
}
@Benchmark
public List<Double> stream() {
return sourceList.stream()
.filter(i -> i % 2 == 0)
.map(Math::sqrt)
.collect(Collectors.toCollection(
() -> new ArrayList<>(sourceList.size() / 2 + 1)));
}
}
結(jié)果:
Benchmark Mode Samples Mean Mean error Units
StreamVsVanilla.stream avgt 10 17.588 0.230 ns/op
StreamVsVanilla.vanilla avgt 10 10.796 0.063 ns/op
正如我預(yù)期的那樣,流實(shí)現(xiàn)速度相當(dāng)慢。JIT能夠內(nèi)聯(lián)所有l(wèi)ambda內(nèi)容,但不會像vanilla版本那樣生成完美簡潔的代碼。
通常,Java 8流不是魔術(shù)。他們無法加速已經(jīng)很好實(shí)現(xiàn)的東西(可能是普通的迭代或Java 5的 - 每個語句都替換為Iterable.forEach()和Collection.removeIf()調(diào)用)。流更多的是編碼方便性和安全性。方便 - 速度權(quán)衡在這里工作。

TA貢獻(xiàn)1796條經(jīng)驗(yàn) 獲得超4個贊
1)您使用基準(zhǔn)測試時間不到1秒。這意味著副作用會對您的結(jié)果產(chǎn)生強(qiáng)烈影響。所以,我增加了你的任務(wù)10次
int max = 10_000_000;
并運(yùn)行你的基準(zhǔn)。我的結(jié)果:
Collections: Elapsed time: 8592999350 ns (8.592999 seconds)
Streams: Elapsed time: 2068208058 ns (2.068208 seconds)
Parallel streams: Elapsed time: 7186967071 ns (7.186967 seconds)
沒有edit(int max = 1_000_000)結(jié)果
Collections: Elapsed time: 113373057 ns (0.113373 seconds)
Streams: Elapsed time: 135570440 ns (0.135570 seconds)
Parallel streams: Elapsed time: 104091980 ns (0.104092 seconds)
這就像你的結(jié)果:流比收集慢。結(jié)論:流初始化/值傳輸花費(fèi)了大量時間。
2)增加任務(wù)流后變得更快(沒關(guān)系),但并行流仍然太慢。怎么了?注意:你有collect(Collectors.toList())命令。收集單個集合實(shí)質(zhì)上會在并發(fā)執(zhí)行時引入性能瓶頸和開銷。可以通過替換來估計開銷的相對成本
collecting to collection -> counting the element count
對于流,它可以通過collect(Collectors.counting())。我得到了結(jié)果:
Collections: Elapsed time: 41856183 ns (0.041856 seconds)
Streams: Elapsed time: 546590322 ns (0.546590 seconds)
Parallel streams: Elapsed time: 1540051478 ns (1.540051 seconds)
那是一項(xiàng)艱巨的任務(wù)?。╥nt max = 10000000)結(jié)論:收集物品需要花費(fèi)大部分時間。最慢的部分是添加到列表中。BTW,簡單ArrayList用于Collectors.toList()。

TA貢獻(xiàn)1797條經(jīng)驗(yàn) 獲得超4個贊
public static void main(String[] args) {
//Calculating square root of even numbers from 1 to N
int min = 1;
int max = 10000000;
List<Integer> sourceList = new ArrayList<>();
for (int i = min; i < max; i++) {
sourceList.add(i);
}
List<Double> result = new LinkedList<>();
//Collections approach
long t0 = System.nanoTime();
long elapsed = 0;
for (Integer i : sourceList) {
if(i % 2 == 0){
result.add( doSomeCalculate(i));
}
}
elapsed = System.nanoTime() - t0;
System.out.printf("Collections: Elapsed time:\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
//Stream approach
Stream<Integer> stream = sourceList.stream();
t0 = System.nanoTime();
result = stream.filter(i -> i%2 == 0).map(i -> doSomeCalculate(i))
.collect(Collectors.toList());
elapsed = System.nanoTime() - t0;
System.out.printf("Streams: Elapsed time:\t\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
//Parallel stream approach
stream = sourceList.stream().parallel();
t0 = System.nanoTime();
result = stream.filter(i -> i%2 == 0).map(i -> doSomeCalculate(i))
.collect(Collectors.toList());
elapsed = System.nanoTime() - t0;
System.out.printf("Parallel streams: Elapsed time:\t %d ns \t(%f seconds)%n", elapsed, elapsed / Math.pow(10, 9));
}
static double doSomeCalculate(int input) {
for(int i=0; i<100000; i++){
Math.sqrt(i+input);
}
return Math.sqrt(input);
}
我稍微更改了代碼,在我的mac book pro上運(yùn)行了8個內(nèi)核,得到了一個合理的結(jié)果:
收藏:經(jīng)歷時間:1522036826 ns(1.522037秒)
流:經(jīng)過的時間:4315833719 ns(4.315834秒)
并行流:經(jīng)過時間:261152901 ns(0.261153秒)
添加回答
舉報