日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

為什么list.sort()比Stream().sorted()更快?

來(lái)源: 責(zé)編: 時(shí)間:2023-09-18 21:41:46 303觀看
導(dǎo)讀看到一個(gè)評(píng)論,里面提到了list.sort()和list.strem().sorted()排序的差異。說(shuō)到list.sort()排序比stream().sorted()排序性能更好。但沒說(shuō)到為什么。有朋友也提到了這一點(diǎn)。本文重新開始,先問是不是,再問為什么。真的更好

看到一個(gè)評(píng)論,里面提到了list.sort()和list.strem().sorted()排序的差異。rvE28資訊網(wǎng)——每日最新資訊28at.com

說(shuō)到list.sort()排序比stream().sorted()排序性能更好。rvE28資訊網(wǎng)——每日最新資訊28at.com

但沒說(shuō)到為什么。rvE28資訊網(wǎng)——每日最新資訊28at.com

rvE28資訊網(wǎng)——每日最新資訊28at.com

有朋友也提到了這一點(diǎn)。rvE28資訊網(wǎng)——每日最新資訊28at.com

本文重新開始,先問是不是,再問為什么。rvE28資訊網(wǎng)——每日最新資訊28at.com

真的更好嗎?

先簡(jiǎn)單寫個(gè) demo。rvE28資訊網(wǎng)——每日最新資訊28at.com

List<Integer> userList = new ArrayList<>();    Random rand = new Random();    for (int i = 0; i < 10000 ; i++) {        userList.add(rand.nextInt(1000));    }    List<Integer> userList2 = new ArrayList<>();    userList2.addAll(userList);    Long startTime1 = System.currentTimeMillis();    userList2.stream().sorted(Comparator.comparing(Integer::intValue)).collect(Collectors.toList());    System.out.println("stream.sort耗時(shí):"+(System.currentTimeMillis() - startTime1)+"ms");    Long startTime = System.currentTimeMillis();    userList.sort(Comparator.comparing(Integer::intValue));    System.out.println("List.sort()耗時(shí):"+(System.currentTimeMillis()-startTime)+"ms");

輸出:rvE28資訊網(wǎng)——每日最新資訊28at.com

stream.sort耗時(shí):62msList.sort()耗時(shí):7ms

由此可見 list 原生排序性能更好。rvE28資訊網(wǎng)——每日最新資訊28at.com

能證明嗎?rvE28資訊網(wǎng)——每日最新資訊28at.com

不一定吧。rvE28資訊網(wǎng)——每日最新資訊28at.com

再把 demo 變換一下,先輸出stream.sort。rvE28資訊網(wǎng)——每日最新資訊28at.com

List<Integer> userList = new ArrayList<>();Random rand = new Random();for (int i = 0; i < 10000 ; i++) {    userList.add(rand.nextInt(1000));}List<Integer> userList2 = new ArrayList<>();userList2.addAll(userList);Long startTime = System.currentTimeMillis();userList.sort(Comparator.comparing(Integer::intValue));System.out.println("List.sort()耗時(shí):"+(System.currentTimeMillis()-startTime)+"ms");Long startTime1 = System.currentTimeMillis();userList2.stream().sorted(Comparator.comparing(Integer::intValue)).collect(Collectors.toList());System.out.println("stream.sort耗時(shí):"+(System.currentTimeMillis() - startTime1)+"ms");

此時(shí)輸出變成了:rvE28資訊網(wǎng)——每日最新資訊28at.com

List.sort()耗時(shí):68msstream.sort耗時(shí):13ms

這能證明上面的結(jié)論錯(cuò)誤了嗎?rvE28資訊網(wǎng)——每日最新資訊28at.com

都不能。rvE28資訊網(wǎng)——每日最新資訊28at.com

兩種方式都不能證明到底誰(shuí)更快。rvE28資訊網(wǎng)——每日最新資訊28at.com

使用這種方式在很多場(chǎng)景下是不夠的,某些場(chǎng)景下,JVM 會(huì)對(duì)代碼進(jìn)行 JIT 編譯和內(nèi)聯(lián)優(yōu)化。rvE28資訊網(wǎng)——每日最新資訊28at.com

Long startTime = System.currentTimeMillis();...System.currentTimeMillis() - startTime

此時(shí),代碼優(yōu)化前后執(zhí)行的結(jié)果就會(huì)非常大。rvE28資訊網(wǎng)——每日最新資訊28at.com

基準(zhǔn)測(cè)試是指通過設(shè)計(jì)科學(xué)的測(cè)試方法、測(cè)試工具和測(cè)試系統(tǒng),實(shí)現(xiàn)對(duì)一類測(cè)試對(duì)象的某項(xiàng)性能指標(biāo)進(jìn)行定量的和可對(duì)比的測(cè)試。rvE28資訊網(wǎng)——每日最新資訊28at.com

基準(zhǔn)測(cè)試使得被測(cè)試代碼獲得足夠預(yù)熱,讓被測(cè)試代碼得到充分的 JIT 編譯和優(yōu)化。rvE28資訊網(wǎng)——每日最新資訊28at.com

下面是通過 JMH 做一下基準(zhǔn)測(cè)試,分別測(cè)試集合大小在 100,10000,100000 時(shí)兩種排序方式的性能差異。rvE28資訊網(wǎng)——每日最新資訊28at.com

import org.openjdk.jmh.annotations.*;import org.openjdk.jmh.infra.Blackhole;import org.openjdk.jmh.results.format.ResultFormatType;import org.openjdk.jmh.runner.Runner;import org.openjdk.jmh.runner.RunnerException;import org.openjdk.jmh.runner.options.Options;import org.openjdk.jmh.runner.options.OptionsBuilder;import java.util.*;import java.util.concurrent.ThreadLocalRandom;import java.util.concurrent.TimeUnit;import java.util.stream.Collectors;@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.MICROSECONDS)@Warmup(iterations = 2, time = 1)@Measurement(iterations = 5, time = 5)@Fork(1)@State(Scope.Thread)public class SortBenchmark {    @Param(value = {"100", "10000", "100000"})    private int operationSize;     private static List<Integer> arrayList;    public static void main(String[] args) throws RunnerException {        // 啟動(dòng)基準(zhǔn)測(cè)試        Options opt = new OptionsBuilder()            .include(SortBenchmark.class.getSimpleName())             .result("SortBenchmark.json")            .mode(Mode.All)            .resultFormat(ResultFormatType.JSON)            .build();        new Runner(opt).run();     }    @Setup    public void init() {        arrayList = new ArrayList<>();        Random random = new Random();        for (int i = 0; i < operationSize; i++) {            arrayList.add(random.nextInt(10000));        }    }    @Benchmark    public void sort(Blackhole blackhole) {        arrayList.sort(Comparator.comparing(e -> e));        blackhole.consume(arrayList);    }    @Benchmark    public void streamSorted(Blackhole blackhole) {        arrayList = arrayList.stream().sorted(Comparator.comparing(e -> e)).collect(Collectors.toList());        blackhole.consume(arrayList);    }}

性能測(cè)試結(jié)果:rvE28資訊網(wǎng)——每日最新資訊28at.com

rvE28資訊網(wǎng)——每日最新資訊28at.com

可以看到,list.sort()效率確實(shí)比stream().sorted()要好。rvE28資訊網(wǎng)——每日最新資訊28at.com

為什么更好?rvE28資訊網(wǎng)——每日最新資訊28at.com

流本身的損耗

java 的 stream 讓我們可以在應(yīng)用層就可以高效地實(shí)現(xiàn)類似數(shù)據(jù)庫(kù) SQL 的聚合操作了,它可以讓代碼更加簡(jiǎn)潔優(yōu)雅。rvE28資訊網(wǎng)——每日最新資訊28at.com

但是,假設(shè)我們要對(duì)一個(gè) list 排序,得先把 list 轉(zhuǎn)成 stream 流,排序完成后需要將數(shù)據(jù)收集起來(lái)重新形成 list,這部份額外的開銷有多大呢?rvE28資訊網(wǎng)——每日最新資訊28at.com

我們可以通過以下代碼來(lái)進(jìn)行基準(zhǔn)測(cè)試:rvE28資訊網(wǎng)——每日最新資訊28at.com

import org.openjdk.jmh.annotations.*;import org.openjdk.jmh.infra.Blackhole;import org.openjdk.jmh.results.format.ResultFormatType;import org.openjdk.jmh.runner.Runner;import org.openjdk.jmh.runner.RunnerException;import org.openjdk.jmh.runner.options.Options;import org.openjdk.jmh.runner.options.OptionsBuilder;import java.util.ArrayList;import java.util.Comparator;import java.util.List;import java.util.Random;import java.util.concurrent.TimeUnit;import java.util.stream.Collectors;@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.MICROSECONDS)@Warmup(iterations = 2, time = 1)@Measurement(iterations = 5, time = 5)@Fork(1)@State(Scope.Thread)public class SortBenchmark3 {    @Param(value = {"100", "10000"})    private int operationSize; // 操作次數(shù)    private static List<Integer> arrayList;    public static void main(String[] args) throws RunnerException {        // 啟動(dòng)基準(zhǔn)測(cè)試        Options opt = new OptionsBuilder()            .include(SortBenchmark3.class.getSimpleName()) // 要導(dǎo)入的測(cè)試類            .result("SortBenchmark3.json")            .mode(Mode.All)            .resultFormat(ResultFormatType.JSON)            .build();        new Runner(opt).run(); // 執(zhí)行測(cè)試    }    @Setup    public void init() {        // 啟動(dòng)執(zhí)行事件        arrayList = new ArrayList<>();        Random random = new Random();        for (int i = 0; i < operationSize; i++) {            arrayList.add(random.nextInt(10000));        }    }    @Benchmark    public void stream(Blackhole blackhole) {        arrayList.stream().collect(Collectors.toList());        blackhole.consume(arrayList);    }    @Benchmark    public void sort(Blackhole blackhole) {        arrayList.stream().sorted(Comparator.comparing(Integer::intValue)).collect(Collectors.toList());        blackhole.consume(arrayList);    }}

方法 stream 測(cè)試將一個(gè)集合轉(zhuǎn)為流再收集回來(lái)的耗時(shí)。rvE28資訊網(wǎng)——每日最新資訊28at.com

方法 sort 測(cè)試將一個(gè)集合轉(zhuǎn)為流再排序再收集回來(lái)的全過程耗時(shí)。rvE28資訊網(wǎng)——每日最新資訊28at.com

測(cè)試結(jié)果如下:rvE28資訊網(wǎng)——每日最新資訊28at.com

rvE28資訊網(wǎng)——每日最新資訊28at.com

可以發(fā)現(xiàn),集合轉(zhuǎn)為流再收集回來(lái)的過程,肯定會(huì)耗時(shí),但是它占全過程的比率并不算高。rvE28資訊網(wǎng)——每日最新資訊28at.com

因此,這部只能說(shuō)是小部份的原因。rvE28資訊網(wǎng)——每日最新資訊28at.com

排序過程

我們可以通過以下源碼很直觀的看到。rvE28資訊網(wǎng)——每日最新資訊28at.com

rvE28資訊網(wǎng)——每日最新資訊28at.com

  • 1 begin方法初始化一個(gè)數(shù)組。
  • 2 accept 接收上游數(shù)據(jù)。
  • 3 end 方法開始進(jìn)行排序。

這里第 3 步直接調(diào)用了原生的排序方法,完成排序后,第 4 步,遍歷向下游發(fā)送數(shù)據(jù)。rvE28資訊網(wǎng)——每日最新資訊28at.com

所以通過源碼,我們也能很明顯地看到,stream()排序所需時(shí)間肯定是 > 原生排序時(shí)間。rvE28資訊網(wǎng)——每日最新資訊28at.com

只不過,這里要量化地搞明白,到底多出了多少,這里得去編譯 jdk 源碼,在第 3 步前后將時(shí)間打印出來(lái)。rvE28資訊網(wǎng)——每日最新資訊28at.com

這一步我就不做了。rvE28資訊網(wǎng)——每日最新資訊28at.com

感興趣的朋友可以去測(cè)一下。rvE28資訊網(wǎng)——每日最新資訊28at.com

不過我覺得這兩點(diǎn)也能很好地回答,為什么list.sort()比Stream().sorted()更快。rvE28資訊網(wǎng)——每日最新資訊28at.com

補(bǔ)充說(shuō)明:rvE28資訊網(wǎng)——每日最新資訊28at.com

  • 本文說(shuō)的 stream() 流指的是串行流,而不是并行流。
  • 絕大多數(shù)場(chǎng)景下,幾百幾千幾萬(wàn)的數(shù)據(jù),開心就好,怎么方便怎么用,沒有必要去計(jì)較這點(diǎn)性能差異。

本文鏈接:http://www.www897cc.com/showinfo-26-10468-0.html為什么list.sort()比Stream().sorted()更快?

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: C++中表達(dá)式的必要性

下一篇: 分布式事務(wù)原理及解決方案

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 泾阳县| 三亚市| 增城市| 通化市| 汶上县| 上饶县| 阿克陶县| 灯塔市| 玉溪市| 扶沟县| 江城| 磐安县| 福泉市| 东乡| 舟山市| 荔波县| 涪陵区| 涞源县| 卢湾区| 繁昌县| 舟山市| 蓬莱市| 义马市| 昆山市| 襄汾县| 河东区| 盐池县| 昭苏县| 大方县| 汉寿县| 信宜市| 木兰县| 富川| 长岭县| 米脂县| 海伦市| 前郭尔| 东平县| 荆州市| 无极县| 始兴县|