java - Comparaison des performances de concaténation de cinq chaînes à l'aide du framework d'analyse comparative JMH

java - Comparaison des performances de concaténation de cinq chaînes à l'aide du framework d'analyse comparative JMH

introduction

Java propose 5 méthodes de concaténation de chaînes, et l'utilisation de + pour concaténer des chaînes est la méthode la plus courante. De plus, il existe StringBuilder, StringBuffer, MessageFormat et StringFormat

pour comparer les performances des cinq méthodes suivantes simplement à partir du temps d'exécution de l'épissage.

Comparaison des résultats

Regardez d'abord les résultats de l'exécution, où Score est le temps d'exécution (subtil) et Error peut être considéré comme une erreur.

Le temps d'exécution du court au long est : + < StringBuilder < StringBuilder < MessageFormat < StringFormat

Benchmark                  Mode  Cnt     Score     Error  Units
JmhTest.testMessageFormat  avgt    5   722.346 ± 134.540  us/op
JmhTest.testStringBase     avgt    5     6.905 ±   2.604  us/op
JmhTest.testStringBuffer   avgt    5     8.291 ±   5.311  us/op
JmhTest.testStringBuilder  avgt    5     7.192 ±   3.861  us/op
JmhTest.testStringFormat   avgt    5  1273.906 ±  69.336  us/op

référence jmh

ajouter des dépendances

<!--基准测试-->
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>1.35</version>
</dependency>
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>1.35</version>
</dependency>

Remarques JMH

@BenchMarkMode Définir le mode de test de référence [méthode ou classe]

@OutPutTimeUnit L'unité de temps par défaut pour rapporter les résultats [classe, méthode]

@Warmup warmup, définir des paramètres de configuration spécifiques tels que les heures, l'heure, etc.

@Measurement est similaire à l'échauffement, mais le paramètre est @Fork lors de la mesure

du test global plusieurs fois

@State définir la portée des objets de configuration, définir le degré de partage entre les threads

@Setup fonction de configuration du thread avant l'exécution, initialisation

@TearDown opérations de traitement post-test 【Méthode】

@BenchMark mark test benchmark [Méthode]

@OperationsPerInvocation effectue une communication multi-opérations avec le benchmark et exécute l'ajustement JMH

  • @BenchMarkMode
    définit le mode d'exécution du test de référence. Vous pouvez choisir de le mettre sur la méthode et de ne prendre effet que pour la méthode.

    Mode.Throughput : mode Débit, obtenez le nombre d'opérations par unité de temps, exécutez la méthode @BenchMark en continu et calculez le débit total de tous les threads de travail.

    Mode.AverageTime : mode Temps moyen, obtenez le temps moyen de chaque opération et calculez le temps moyen de tous les threads de travail.

    Mode.SimpleTime : mode d'échantillonnage temporel, qui échantillonne l'heure de chaque fonction d'opération, exécute les fonctions @BenchMark en continu et extrait de manière aléatoire le temps requis pour l'opération.

    Mode.SingleShotTime : mode de déclenchement unique, testez le temps d'une seule opération, exécutez la fonction @BenchMark en continu, exécutez-la une seule fois et calculez le temps : ce mode n'exécute la fonction @BenchMark qu'une seule fois, elle doit donc se réchauffer, si la valeur de référence est petite, utilisez l'échantillonnage SimpleTime Pattern.

    Mode.All : pas de mode, utilisez tous les modes de base, le meilleur effet.

écrire le code de test

Exécutez la méthode principale pour démarrer le test et attendez patiemment que le test soit terminé.

import org.openjdk.jmh.annotations.*;
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.text.MessageFormat;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime) //基准测试的默认模式
@OutputTimeUnit(TimeUnit.MICROSECONDS) //时间单位:纳秒、微妙、毫秒、秒、分、时
@State(Scope.Thread)
@Fork(1) //进程数一般设置为1
//@Threads(1) //线程数
@Warmup(iterations = 2,time = 2) //预热迭代次数,time控制每次迭代的间隔时间(默认秒)
@Measurement(iterations = 5,time = 2) //测量迭代次数,time控制每次迭代的间隔时间(默认秒)
public class JmhTest {
    private int _loop = 1000;
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(JmhTest.class.getSimpleName()).build();
        new Runner(opt).run();
    }
    //StringBuffer
    @Benchmark //被测试的方法
    public void testStringBuffer() {
        for(int i = 0; i< _loop; i++){
            StringBuffer sbr = new StringBuffer();
            String s = sbr.append("1111").append(",")
                    .append("2222").append(",")
                    .append("3333").append(",")
                    .append("4444").toString();
        }
    }
    //StringBuilder
    @Benchmark //被测试的方法
    public void testStringBuilder() {
        for(int i = 0; i< _loop; i++){
            StringBuilder sbr = new StringBuilder();
            String s = sbr.append("1111").append(",")
                    .append("2222").append(",")
                    .append("3333").append(",")
                    .append("4444").toString();
        }
    }
    //MessageFormat
    @Benchmark
    public void testMessageFormat() {
        for(int i = 0; i< _loop; i++){
            String s = MessageFormat.format("{0},{1},{2},{3}","1111","2222","3333","4444");
        }
    }
    //String.format
    @Benchmark
    public void testStringFormat() {
        for(int i = 0; i< _loop; i++){
            String s = String.format("%s,%s,%s,%s","1111","2222","3333","4444");
        }
    }
    //字符串拼接
    @Benchmark
    public void testStringBase() {
        for(int i = 0; i< _loop; i++){
            String s = "1111";
            s+=",2222";
            s+=",3333";
            s+=",4444";
        }
    }

}

Description des résultats des tests

Ce qui précède évalue en réalité 5 fonctions. La configuration du test est que chaque fonction est préchauffée et exécutée une fois, et le temps d'exécution moyen des 5 fois suivantes est compté.

True pour utiliser le test de mode Mode.AverageTime, la sortie après l'exécution de chaque fonction est :

Result "com.cnpc.epai.researchdata.data.service.JmhTest.testStringFormat":
  1254.609 ±(99.9%) 174.543 us/op [Average]
  (min, avg, max) = (1174.821, 1254.609, 1282.413), stdev = 45.328
  CI (99.9%): [1080.066, 1429.151] (assumes normal distribution)

Le résultat final de l'exécution est :

Benchmark                  Mode  Cnt     Score     Error  Units
JmhTest.testMessageFormat  avgt    5   722.346 ± 134.540  us/op
JmhTest.testStringBase     avgt    5     6.905 ±   2.604  us/op
JmhTest.testStringBuffer   avgt    5     8.291 ±   5.311  us/op
JmhTest.testStringBuilder  avgt    5     7.192 ±   3.861  us/op
JmhTest.testStringFormat   avgt    5  1273.906 ±  69.336  us/op

Où Score est le temps d'exécution (subtil) et Error est l'erreur ;

en conclusion:

1. La manière d’utiliser StringBuilder est la plus efficace.
2. Si vous n'effectuez pas d'épissage de chaîne dans le corps de la boucle, utilisez simplement + directement.
3. Si l'épissage de chaînes est effectué dans un scénario simultané, StringBuffer doit être utilisé à la place de StringBuilder.

おすすめ

転載: blog.csdn.net/xxj_jing/article/details/129680765