成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開發(fā) 測試
本文主要介紹關于 list.sort() 和 list.strem().sorted() 排序的差異,到底哪個性能更好一些。

看到一個評論,里面提到了list.sort()和list.strem().sorted()排序的差異。

說到list.sort()排序比stream().sorted()排序性能更好。

但沒說到為什么。

有朋友也提到了這一點。

本文重新開始,先問是不是,再問為什么。

真的更好嗎?

先簡單寫個 demo。

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耗時:"+(System.currentTimeMillis() - startTime1)+"ms");

    Long startTime = System.currentTimeMillis();
    userList.sort(Comparator.comparing(Integer::intValue));
    System.out.println("List.sort()耗時:"+(System.currentTimeMillis()-startTime)+"ms");

輸出:

stream.sort耗時:62ms
List.sort()耗時:7ms

由此可見 list 原生排序性能更好。

能證明嗎?

不一定吧。

再把 demo 變換一下,先輸出stream.sort。

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()耗時:"+(System.currentTimeMillis()-startTime)+"ms");

Long startTime1 = System.currentTimeMillis();
userList2.stream().sorted(Comparator.comparing(Integer::intValue)).collect(Collectors.toList());
System.out.println("stream.sort耗時:"+(System.currentTimeMillis() - startTime1)+"ms");

此時輸出變成了:

List.sort()耗時:68ms
stream.sort耗時:13ms

這能證明上面的結論錯誤了嗎?

都不能。

兩種方式都不能證明到底誰更快。

使用這種方式在很多場景下是不夠的,某些場景下,JVM 會對代碼進行 JIT 編譯和內(nèi)聯(lián)優(yōu)化。

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

此時,代碼優(yōu)化前后執(zhí)行的結果就會非常大。

基準測試是指通過設計科學的測試方法、測試工具和測試系統(tǒng),實現(xiàn)對一類測試對象的某項性能指標進行定量的和可對比的測試。

基準測試使得被測試代碼獲得足夠預熱,讓被測試代碼得到充分的 JIT 編譯和優(yōu)化。

下面是通過 JMH 做一下基準測試,分別測試集合大小在 100,10000,100000 時兩種排序方式的性能差異。

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 {
        // 啟動基準測試
        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);
    }
}

性能測試結果:

可以看到,list.sort()效率確實比stream().sorted()要好。

為什么更好?

流本身的損耗

java 的 stream 讓我們可以在應用層就可以高效地實現(xiàn)類似數(shù)據(jù)庫 SQL 的聚合操作了,它可以讓代碼更加簡潔優(yōu)雅。

但是,假設我們要對一個 list 排序,得先把 list 轉成 stream 流,排序完成后需要將數(shù)據(jù)收集起來重新形成 list,這部份額外的開銷有多大呢?

我們可以通過以下代碼來進行基準測試:

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 {
        // 啟動基準測試
        Options opt = new OptionsBuilder()
            .include(SortBenchmark3.class.getSimpleName()) // 要導入的測試類
            .result("SortBenchmark3.json")
            .mode(Mode.All)
            .resultFormat(ResultFormatType.JSON)
            .build();
        new Runner(opt).run(); // 執(zhí)行測試
    }

    @Setup
    public void init() {
        // 啟動執(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 測試將一個集合轉為流再收集回來的耗時。

方法 sort 測試將一個集合轉為流再排序再收集回來的全過程耗時。

測試結果如下:

可以發(fā)現(xiàn),集合轉為流再收集回來的過程,肯定會耗時,但是它占全過程的比率并不算高。

因此,這部只能說是小部份的原因。

排序過程

我們可以通過以下源碼很直觀的看到。

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

這里第 3 步直接調用了原生的排序方法,完成排序后,第 4 步,遍歷向下游發(fā)送數(shù)據(jù)。

所以通過源碼,我們也能很明顯地看到,stream()排序所需時間肯定是 > 原生排序時間。

只不過,這里要量化地搞明白,到底多出了多少,這里得去編譯 jdk 源碼,在第 3 步前后將時間打印出來。

這一步我就不做了。

感興趣的朋友可以去測一下。

不過我覺得這兩點也能很好地回答,為什么list.sort()比Stream().sorted()更快。

補充說明:

  • 本文說的 stream() 流指的是串行流,而不是并行流。
  • 絕大多數(shù)場景下,幾百幾千幾萬的數(shù)據(jù),開心就好,怎么方便怎么用,沒有必要去計較這點性能差異。
責任編輯:趙寧寧 來源: 技術老男孩
相關推薦

2021-11-05 07:13:46

Python

2021-01-13 10:51:08

PromissetTimeout(函數(shù)

2020-11-09 10:01:29

Python乘法位運算

2024-10-28 21:11:52

2022-04-28 12:00:34

Go泛型版排序

2024-02-22 15:31:46

Python排序

2014-08-29 09:56:47

排序數(shù)組編程技巧

2022-11-10 15:32:29

2019-09-16 12:00:03

constC編程語言

2015-07-31 16:29:15

DockerJavaLinux

2019-04-24 08:00:00

HTTPSHTTP前端

2021-12-27 07:10:26

ClassmethodStaticmetho函數(shù)

2016-12-14 12:02:01

StormHadoop大數(shù)據(jù)

2017-02-14 14:20:02

StormHadoop

2013-08-15 10:05:16

代碼

2020-09-19 17:59:21

sorted()Python函數(shù)

2023-09-20 00:06:30

Python代碼函數(shù)

2024-06-26 10:50:35

2024-08-19 00:10:05

RocketMQ應用SDK

2020-03-18 14:08:48

Windows操作系統(tǒng)功能
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 999久久久 | 国产一区二区三区色淫影院 | 国产激情免费视频 | 99久久成人 | 精品一区二区三区中文字幕 | 韩日一区二区 | 亚洲国产精品久久久久 | 国产高清免费视频 | www.日韩在线 | 福利国产| 999久久久免费精品国产 | 熟女毛片 | aaa在线 | 国产亚洲精品美女久久久久久久久久 | 狠狠操网站 | 黄色av网站在线免费观看 | 亚洲理论在线观看电影 | 国产精品久久久久久久久久久久久久 | 欧美 日韩 国产 成人 | 日韩电影在线一区 | 国产原创视频 | www久久国产 | 中文字幕在线免费视频 | 日韩国产一区二区三区 | 操皮视频 | 天天干天天草 | 一区二区三区在线观看视频 | 毛片入口| 一区二区高清 | 国产视频h | 在线一区二区三区 | 国产高清一区二区三区 | 99中文字幕 | 狠狠综合久久av一区二区老牛 | 久久国产欧美一区二区三区精品 | 国产高清在线精品一区二区三区 | 岛国毛片在线观看 | 一二三区av | 国产高清自拍视频在线观看 | 午夜视频在线观看网址 | 日日夜夜精品视频 |