橘子学JDK之JMH-02(BenchmarkModes)

news2024/12/25 13:06:59

一、案例二代码

这次我们来搞一下官网文档的第二个案例,我删除了一些没用的注释,然后对代码做了一下注释的翻译,可以看一下意思。

package com.levi;

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.util.concurrent.TimeUnit;

// 预热注解,修改为只预热一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Warmup(iterations = 1,time = 1)
// 测试执行注解,修改为只执行一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Measurement(iterations = 1,time = 1)
public class JMHSample_02_01_BenchmarkModes {

    /*
     * Mode.Throughput, as stated in its Javadoc, measures the raw throughput by
     * continuously calling the benchmark method in a time-bound iteration, and
     * counting how many times we executed the method.
     *
     * We are using the special annotation to select the units to measure in,
     * although you can use the default.
     *
     * AI直译:Mode.Throughput,如其Javadoc所述,通过在时间限制的迭代中连续调用基准方法,
     * 并计算我们执行该方法的次数来衡量原始吞吐量。我们正在使用特殊注解来选择要测量的单位,尽管你可以使用默认值。
     *
     * 我根据我的理解还是说几句人话吧,他的意思是我们之前不是在案例1中输出的是吞吐量的测试指标吗,这里的意思是你可以
     * 使用@BenchmarkMode这个注解,里面设置参数Mode.Throughput一样可以是通过吞吐量的指标的,或者说你不设置,默认
     * 本身就是吞吐量,我们第一个案例就是默认的。
     * 所以我们在第一个方法上看到新出现的两个注解
     * @BenchmarkMode:设置计算指标
     * @OutputTimeUnit:计算模式对应的单位
     */

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    @OutputTimeUnit(TimeUnit.SECONDS)
    public void measureThroughput() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }

    /*
     * Mode.AverageTime measures the average execution time, and it does it
     * in the way similar to Mode.Throughput.
     * 在性能测试或基准测试的背景下,Mode.AverageTime(平均时间模式)测量了给定操作或代码片段的平均执行时间。
     * 该模式计算了每次调用被测试代码所花费的平均时间。它与Mode.Throughput(吞吐量模式)相似,两种模式都专注于性能测量,
     * 但它们在优先考虑的性能方面存在差异。以下是Mode.AverageTime和Mode.Throughput之间的简要比较:
     * 平均时间:该模式计算每个操作或调用的平均执行时间。它提供了关于单个操作平均执行时间的信息。
     * 吞吐量:另一方面,Mode.Throughput关注的是在给定时间内完成的操作速率。它衡量每单位时间内可以执行多少操作,通常是每秒。
     * 它提供了系统在高负载下处理大量操作的效率信息。
     * 虽然两种模式都提供了有关性能的有价值的信息,但它们服务于不同的目的,可能适用于不同类型的性能分析。
     * Mode.AverageTime适用于了解单个操作的平均延迟或执行时间,而Mode.Throughput更适用于在指定时间范围内最大化完成的操作数量。
     *
     *
     * Some might say it is the reciprocal throughput, and it really is.
     * There are workloads where measuring times is more convenient though.
     * 有人说,这个指标是吞吐量的倒数,你也可以这么理解,不过有时候你测试的时候,统计时间维度是更加直观的。
     *
     * 换言之,这个是统计你方法的执行平均时间的,所以看起来比吞吐量更加直观,毕竟耗时是我们普遍关心的第一指标
     */
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureAvgTime() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }

    /*
     * Mode.SampleTime samples the execution time. With this mode, we are
     * still running the method in a time-bound iteration, but instead of
     * measuring the total time, we measure the time spent in *some* of
     * the benchmark method calls.
     *
     * Mode.SampleTime是用于对方法执行时间进行采样的一种模式。在这种模式下,我们仍然在一个有时间限制的迭代中运行方法,
     * 但不再测量总时间,而是测量一部分基准方法调用所花费的时间。使用Mode.SampleTime模式时,
     * 基准测试框架会定期中断方法的执行并记录经过的时间。通过只对部分调用进行采样,可以减少与连续时间测量相关的开销,
     * 同时仍能提供有关方法执行时间分布的有意义数据,而不仅仅关注整体持续时间。这种模式对于识别执行时间的变化非常有用,
     * 特别是如果方法的某些部分可能具有不同的性能特点或表现出间歇性行为。它使开发人员能够了解方法在不同条件下的性能表现,
     * 并帮助优化其性能。
     *
     * This allows us to infer the distributions, percentiles, etc.
     * JMH also tries to auto-adjust sampling frequency: if the method
     * is long enough, you will end up capturing all the samples.
     * 这样可以让我们推断出分布情况、百分位数等。JMH 还会尝试自动调整采样频率:如果方法足够长,你最终会捕获到所有的样本
     *
     * 这个解释的不明确,我们待会通过现象来看一下具体啥意思。
     */
    @Benchmark
    @BenchmarkMode(Mode.SampleTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureSamples() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }

    /*
     * Mode.SingleShotTime measures the single method invocation time. As the Javadoc
     * suggests, we do only the single benchmark method invocation. The iteration
     * time is meaningless in this mode: as soon as benchmark method stops, the
     * iteration is over.
     *
     * Mode.SingleShotTime测量的是单个方法调用的时间。正如Javadoc所建议的,我们只进行一次基准方法的调用。
     * 在这种模式下,迭代时间是没有意义的:一旦基准方法停止,迭代就结束了。
     *
     * This mode is useful to do cold startup tests, when you specifically
     * do not want to call the benchmark method continuously.
     * 这种模式在进行冷启动测试时非常有用,当你不想连续调用基准方法时。
     *
     * 说白了就是只测试一次,就跟你跑main函数一样的,没有预热,就是冷启动的测试。
     */
    @Benchmark
    @BenchmarkMode(Mode.SingleShotTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureSingleShot() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }

    /*
     * We can also ask for multiple benchmark modes at once. All the tests
     * above can be replaced with just a single test like this:
     *
     * 这个注解还能写数组,指定多种测试指标,一起生效
     */
    @Benchmark
    @BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime, Mode.SingleShotTime})
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureMultiple() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }

    /*
     * Or even...
     * 如果你懒得写很多模式,你还能直接用Mode.All来表示全部的模式
     */
    @Benchmark
    @BenchmarkMode(Mode.All)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureAll() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_02_01_BenchmarkModes.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }
}

二、@BenchmarkMode

我们先不急着运行程序,我们在看完上面的例子之后可以看到这次出现了一个新的注解,就是
@BenchmarkMode

@Inherited
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface BenchmarkMode {
    Mode[] value();
}

这个注解我们看到,作用的位置就是方法和类上面,你要是标注在类上,那就这个类所有的方法都按照这个配置生效了。
而且我们注意到他有一个变量,是Mode类型的数组,注意是数组,也就是可以传入多个。我们看一下这个Mode类型是啥。

public enum Mode {
    Throughput("thrpt", "Throughput, ops/time"),
    AverageTime("avgt", "Average time, time/op"),
    SampleTime("sample", "Sampling time"),
    SingleShotTime("ss", "Single shot invocation time"),
    All("all", "All benchmark modes");
}

就是个枚举类型,总共五个类型,我们上面的注释其实也标注了这五个类型的各自的作用。

三、 @OutputTimeUnit

与@BenchmarkMode 配套的还有一个注解就是@OutputTimeUnit。

@Inherited
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OutputTimeUnit {
    TimeUnit value();
}

他的作用就是你输出指标的时间单位,没别的了。OK,我们在大致有个了解之后,我们开始通过执行程序来看一下结果,加深我们对于注解的理解。

四、执行程序

鉴于我们这里这次一次写了N个方法测试,输出的报告巨长,我们这里就一个一个的测试,这样方便观察。

1、测试吞吐模式:measureThroughput

package com.levi;

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.util.concurrent.TimeUnit;

// 预热注解,修改为只预热一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Warmup(iterations = 1,time = 1)
// 测试执行注解,修改为只执行一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Measurement(iterations = 1,time = 1)
public class JMHSample_02_01_BenchmarkModes {

    /*
     * Mode.Throughput, as stated in its Javadoc, measures the raw throughput by
     * continuously calling the benchmark method in a time-bound iteration, and
     * counting how many times we executed the method.
     *
     * We are using the special annotation to select the units to measure in,
     * although you can use the default.
     *
     * AI直译:Mode.Throughput,如其Javadoc所述,通过在时间限制的迭代中连续调用基准方法,
     * 并计算我们执行该方法的次数来衡量原始吞吐量。我们正在使用特殊注解来选择要测量的单位,尽管你可以使用默认值。
     *
     * 我根据我的理解还是说几句人话吧,他的意思是我们之前不是在案例1中输出的是吞吐量的测试指标吗,这里的意思是你可以
     * 使用@BenchmarkMode这个注解,里面设置参数Mode.Throughput一样可以是通过吞吐量的指标的,或者说你不设置,默认
     * 本身就是吞吐量,我们第一个案例就是默认的。
     * 所以我们在第一个方法上看到新出现的两个注解
     * @BenchmarkMode:设置计算指标
     * @OutputTimeUnit:计算模式对应的单位
     */

    @Benchmark
    @BenchmarkMode(Mode.Throughput)
    @OutputTimeUnit(TimeUnit.SECONDS)
    public void measureThroughput() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_02_01_BenchmarkModes.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }
}

运行结果为:
Benchmark :JMHSample_02_01_BenchmarkModes.measureThroughput
Mode :thrpt
Cnt : 因为我控制了1次,所以这里没东西
Score :9.160 这个分数在吞吐这里其实就是你执行的吞吐量,因为我写的@OutputTimeUnit(TimeUnit.SECONDS)单位是秒,所以意思就是一秒能执行9.16次。
Error :没输出
Units:ops/s
我们看到这个吞吐量其实和我们在第一个案例测试的差不多,其实他就是默认的。你不写就是他。

2、测试平均时间模式:measureAvgTime

package com.levi;

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.util.concurrent.TimeUnit;

// 预热注解,修改为只预热一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Warmup(iterations = 1,time = 1)
// 测试执行注解,修改为只执行一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Measurement(iterations = 1,time = 1)
public class JMHSample_02_01_BenchmarkModes {

   
    /*
     * Mode.AverageTime measures the average execution time, and it does it
     * in the way similar to Mode.Throughput.
     * 在性能测试或基准测试的背景下,Mode.AverageTime(平均时间模式)测量了给定操作或代码片段的平均执行时间。
     * 该模式计算了每次调用被测试代码所花费的平均时间。它与Mode.Throughput(吞吐量模式)相似,两种模式都专注于性能测量,
     * 但它们在优先考虑的性能方面存在差异。以下是Mode.AverageTime和Mode.Throughput之间的简要比较:
     * 平均时间:该模式计算每个操作或调用的平均执行时间。它提供了关于单个操作平均执行时间的信息。
     * 吞吐量:另一方面,Mode.Throughput关注的是在给定时间内完成的操作速率。它衡量每单位时间内可以执行多少操作,通常是每秒。
     * 它提供了系统在高负载下处理大量操作的效率信息。
     * 虽然两种模式都提供了有关性能的有价值的信息,但它们服务于不同的目的,可能适用于不同类型的性能分析。
     * Mode.AverageTime适用于了解单个操作的平均延迟或执行时间,而Mode.Throughput更适用于在指定时间范围内最大化完成的操作数量。
     *
     *
     * Some might say it is the reciprocal throughput, and it really is.
     * There are workloads where measuring times is more convenient though.
     * 有人说,这个指标是吞吐量的倒数,你也可以这么理解,不过有时候你测试的时候,统计时间维度是更加直观的。
     *
     * 换言之,这个是统计你方法的执行平均时间的,所以看起来比吞吐量更加直观,毕竟耗时是我们普遍关心的第一指标
     */
    @Benchmark
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureAvgTime() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_02_01_BenchmarkModes.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }
}

运行结果如下:
Benchmark :JMHSample_02_01_BenchmarkModes.measureAvgTime
Mode:avgt 平均统计模式
Cnt :同上
Score:108407.350
Error :没错误,不输出
Units:us/op 其实你能看出来,他是时间除以执行次数,所以就是吞吐量的倒数,吞吐量的意思是每秒能执行几次,这里就是执行一次需要几秒,不就是平均时间吗。只是我指定的时间单位是@OutputTimeUnit(TimeUnit.MICROSECONDS)微秒,所以这里自然也就是这个单位。
他主打的是一个平均耗时。

3、测试统计时间:measureSamples

package com.levi;

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.util.concurrent.TimeUnit;

// 预热注解,修改为只预热一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Warmup(iterations = 1,time = 1)
// 测试执行注解,修改为只执行一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Measurement(iterations = 1,time = 1)
public class JMHSample_02_01_BenchmarkModes {
    /*
     * Mode.SampleTime samples the execution time. With this mode, we are
     * still running the method in a time-bound iteration, but instead of
     * measuring the total time, we measure the time spent in *some* of
     * the benchmark method calls.
     *
     * Mode.SampleTime是用于对方法执行时间进行采样的一种模式。在这种模式下,我们仍然在一个有时间限制的迭代中运行方法,
     * 但不再测量总时间,而是测量一部分基准方法调用所花费的时间。使用Mode.SampleTime模式时,
     * 基准测试框架会定期中断方法的执行并记录经过的时间。通过只对部分调用进行采样,可以减少与连续时间测量相关的开销,
     * 同时仍能提供有关方法执行时间分布的有意义数据,而不仅仅关注整体持续时间。这种模式对于识别执行时间的变化非常有用,
     * 特别是如果方法的某些部分可能具有不同的性能特点或表现出间歇性行为。它使开发人员能够了解方法在不同条件下的性能表现,
     * 并帮助优化其性能。
     *
     * This allows us to infer the distributions, percentiles, etc.
     * JMH also tries to auto-adjust sampling frequency: if the method
     * is long enough, you will end up capturing all the samples.
     * 这样可以让我们推断出分布情况、百分位数等。JMH 还会尝试自动调整采样频率:如果方法足够长,你最终会捕获到所有的样本
     *
     * 这个解释的不明确,我们待会通过现象来看一下具体啥意思。
     */
    @Benchmark
    @BenchmarkMode(Mode.SampleTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureSamples() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_02_01_BenchmarkModes.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }
}

在这里插入图片描述
他是以一种分布统计的方式输出的测试指标,单位还是平均时间耗时,等于说百分之99的测试跑一次是109707.264us的耗时,他内部给你做了一个测试,拆分出来测的,测出这么个结果来。
能看出来一个波动,和你实现的代码稳定性,而且他是抽样测试,不会都给你统计,比如我们设置的跑1轮,每轮一秒。可能这一秒跑了一万次,他不会像吞吐和平均那个样都算进去,他是一个抽样,可能抽了前面后面,没取中间。可能压根就是抽了前面。是一个分布统计。

4、测试只跑一次:measureSingleShot

package com.levi;

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.util.concurrent.TimeUnit;

// 预热注解,修改为只预热一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Warmup(iterations = 1,time = 1)
// 测试执行注解,修改为只执行一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Measurement(iterations = 1,time = 1)
public class JMHSample_02_01_BenchmarkModes {
    /*
     * Mode.SingleShotTime measures the single method invocation time. As the Javadoc
     * suggests, we do only the single benchmark method invocation. The iteration
     * time is meaningless in this mode: as soon as benchmark method stops, the
     * iteration is over.
     *
     * Mode.SingleShotTime测量的是单个方法调用的时间。正如Javadoc所建议的,我们只进行一次基准方法的调用。
     * 在这种模式下,迭代时间是没有意义的:一旦基准方法停止,迭代就结束了。
     *
     * This mode is useful to do cold startup tests, when you specifically
     * do not want to call the benchmark method continuously.
     * 这种模式在进行冷启动测试时非常有用,当你不想连续调用基准方法时。
     *
     * 说白了就是只测试一次,就跟你跑main函数一样的,没有预热,就是冷启动的测试。
     */
    @Benchmark
    @BenchmarkMode(Mode.SingleShotTime)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureSingleShot() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_02_01_BenchmarkModes.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }
}

执行结果如下:
在这里插入图片描述
这就是测试冷启动的,没预热,就是直接跑,你也能看到单位是us/op。还是执行一次要多久。还是个平均值,只不过就是没预热直接开跑的。就跑一次。

5、测试多种模式组合:measureMultiple

package com.levi;

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.util.concurrent.TimeUnit;

// 预热注解,修改为只预热一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Warmup(iterations = 1,time = 1)
// 测试执行注解,修改为只执行一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Measurement(iterations = 1,time = 1)
public class JMHSample_02_01_BenchmarkModes {

    /*
     * We can also ask for multiple benchmark modes at once. All the tests
     * above can be replaced with just a single test like this:
     *
     * 这个注解还能写数组,指定多种测试指标,一起生效
     */
    @Benchmark
    @BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime, Mode.SingleShotTime})
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureMultiple() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_02_01_BenchmarkModes.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }
}

因为我们前面看了Mode是一个数组,所以可以传入多个模式。结果就是一起统计输出了。
在这里插入图片描述

6、测试全量模式:measureAll

package com.levi;

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.util.concurrent.TimeUnit;

// 预热注解,修改为只预热一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Warmup(iterations = 1,time = 1)
// 测试执行注解,修改为只执行一轮,每轮只跑一秒,默认是5,5这里改为1,1
@Measurement(iterations = 1,time = 1)
public class JMHSample_02_01_BenchmarkModes {
    /*
     * Or even...
     * 如果你懒得写很多模式,你还能直接用Mode.All来表示全部的模式
     */
    @Benchmark
    @BenchmarkMode(Mode.All)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    public void measureAll() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(100);
    }

    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(JMHSample_02_01_BenchmarkModes.class.getSimpleName())
                .forks(1)
                .build();

        new Runner(opt).run();
    }
}

自然就是全部的统计都输出了:和上面一样。
在这里插入图片描述
你也可以看他的单位就知道他输出的计算方式了,次数除以时间,那就是平均时间的执行次数,就是吞吐。
时间除以次数,就是统计的某种模式下的平均时间。

五、总结

没啥总结的就是那两个注解,很详细了。

六、参考链接

1、JMH官方文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1579438.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解JVM后端优化技术-方法内联

相关系列 深入理解JVM后端优化技术-逃逸分析(Escape Analysis)-CSDN博客 深入理解JVM后端优化技术-锁消除(Lock Elision)-CSDN博客 深入理解JVM后端优化技术-锁粗化(Lock Coarsening)-CSDN博客 jvm只是负责依次将字节码指令逐次转换成机器码。而在转换过程中&#x…

智能电表(AMI):革新电力行业的利器

近年来,随着电力行业的不断发展和科技的进步,智能电表(AMI)作为一种新型的电能测量设备,逐渐引起了人们的关注。AMI不仅具有传统电表的计量功能,还具备远程通信、数据采集、实时监测和多种数据分析等多功能…

(3)(3.1) 英特尔Realsense深度摄像头(二)

文章目录 前言 5 配置ArduPilot 6 地面测试:飞行前验证 7 飞行测试 8 实验 9 数据闪存记录 前言 本文介绍如何将英特尔 Realsense 深度摄像头(Intel Realsense Depth Camera)与 ArduPilot 配合使用,以实现避障(obstacle avoidance)。该方法使用在…

Linux(CentOS7)部署 y-api 接口管理平台

目录 前言 前置环境 mongodb node 安装 y-api 部署页面 启动 y-api 基本使用教程 前言 前后端分离时代,前后端通过接口文档来协作开发项目。一般开发过程中,由后端先编写接口文档,然后交付给前端,这时候前后端都根据这个…

Linux/Lame

Lame 今天随便乱逛发现这台机器貌似是 HackTheBox 平台的第一台机器,而且我还没做过,从简介上来看的话是一台很简单的机器,快快的玩一下 Enumeration nmap 首先用 nmap 扫描一下常见的端口,发现系统对外开放了 21,22,139,445 端…

如何在CentOS安装Nexus容器无公网IP远程管理本地仓库

文章目录 1. Docker安装Nexus2. 本地访问Nexus3. Linux安装Cpolar4. 配置Nexus界面公网地址5. 远程访问 Nexus界面6. 固定Nexus公网地址7. 固定地址访问Nexus Nexus是一个仓库管理工具,用于管理和组织软件构建过程中的依赖项和构件。它与Maven密切相关,可…

免费专利下载网站(亲测有效!无需注册登录)

1.中国专利全文下载 本数据库收录了自1985年以来的全部中国专利数据摘要及全文,包括中国专利申请公开说明书、授权公告说明书,涵盖全部发明专利、实用新型专利、外观设计专利。药物在线已开发中国专利全文下载极速版!支持专利全文在线浏览,专…

Django交易商场

Hello,我是小恒不会java 最近学习django,写了一个demo,学到了不少东西。 我在GitHub上开源了,提示‘自行查看代码,维护,运行’。 最近有事,先发布代码了,我就随缘维护更新吧 介绍: 定…

计算机的发展趋势

本文 我们来说计算机的发展趋势 目前来讲 计算机是朝着 巨型化 微型化 网络化 智能化发展 巨型化 指功能巨型化 是指其高速运算、大存储容量和强功能的巨型计算机。其运算能力一般在每秒百亿次以上、内存容量在几百兆字节以上。 主要用于航空航天、军事、气象、人工智能、生…

FME学习之旅---day21

我们付出一些成本,时间的或者其他,最终总能收获一些什么。 教程:AutoCAD 变换 相关的文章 为您的 DWG 赋予一些样式:使用 DWGStyler、模板文件、块等 FME数据检查器在显示行的方式上受到限制。它只能显示线条颜色,而…

Linux锁的使用

一、临界资源与临界区 多线程会共享例如全局变量等资源&#xff0c;我们把会被多个执行流访问的资源称为临界资源&#xff0c;我们是通过代码访问临界资源的&#xff0c;而我们访问临界资源的那部分代码称为临界区。 实现一个抢票系统 只有一个线程抢票时 #include <ios…

雷达学习之多普勒频率

一、多普勒频率如何产生&#xff1f; 雷达的原理是发射一些无线电脉冲来探测目标&#xff0c;并通过回波的延时来计算目标与雷达的距离&#xff0c;但当目标为运动物体时&#xff0c;在回波向目标传输的同时&#xff0c;目标也会远离或接近回波&#xff0c;所以会导致回波信号…

CDN加速原理那些事

名词解释 CNAME记录&#xff08;CNAME record&#xff09; CNAME即别名( Canonical Name )&#xff1b;可以用来把一个域名解析到另一个域名&#xff0c;当 DNS 系统在查询 CNAME 左面的名称的时候&#xff0c;都会转向 CNAME 右面的名称再进行查询&#xff0c;一直追踪到最后…

vue 中使 date/time/datetime 类型的 input 支持 placeholder 方法

一般在开发时&#xff0c;设置了 date/time/datetime 等类型的 input 属性 placeholder 提示文本时&#xff0c; 发现实际展示中却并不生效&#xff0c;如图&#xff1a; 处理后效果如图&#xff1a; 处理逻辑 判断表单项未设置值时&#xff0c;则设置其伪类样式&#xff0c;文…

Pillow教程11:九宫格切图的实现方法(安排!!!)

---------------Pillow教程集合--------------- Python项目18&#xff1a;使用Pillow模块&#xff0c;随机生成4位数的图片验证码 Python教程93&#xff1a;初识Pillow模块&#xff08;创建Image对象查看属性图片的保存与缩放&#xff09; Pillow教程02&#xff1a;图片的裁…

ctf_show笔记篇(web入门---SSTI)

前言 模板引擎 模板引擎是为了让用户界面以及业务数据分离开才产生的&#xff0c;模板引擎会生成特定的文档&#xff0c;然后通过模板引擎生成前端html代码&#xff0c;然后再获取用户数据再放到渲染函数里渲染&#xff0c;最后将生成的html代码个渲染好的数据结合拿给浏览器呈…

【Git教程】(十)版本库之间的依赖 —— 项目与子模块之间的依赖、与子树之间的依赖 ~

Git教程 版本库之间的依赖 1️⃣ 与子模块之间的依赖2️⃣ 与子树之间的依赖&#x1f33e; 总结 在 Git 中&#xff0c;版本库是发行单位&#xff0c;代表的是一个版本&#xff0c;而分支或标签则只能被创建在版本库这个整体中。如果一个项目中包含了若干个子项目&#xff0c;…

学习赚钱两不误--全自动挂机软件(网心云)

1、简介 程序员的工作环境程序员的工作环境最多的就是网络资源&#xff0c;所以我们工作中有很多的闲置网络资源&#xff0c;不白嫖有点浪费哈。下面就给大家介绍一下免费分享上行带宽赚钱的平台--网心云 优点&#xff1a; &#xff08;1&#xff09;平台大、靠谱、稳定 &a…

四川易点慧电子商务抖音小店可靠购物

在当下这个信息爆炸的时代&#xff0c;电子商务的崛起不仅改变了人们的购物习惯&#xff0c;也催生了众多新兴的电商平台。四川易点慧电子商务抖音小店便是其中的佼佼者&#xff0c;以其独特的魅力和可靠性&#xff0c;赢得了广大消费者的青睐。 一、平台背景实力雄厚 四川易点…

3、最大池化maxinmum pooling

了解有关最大池化特征提取的更多信息。 简介 在第二课中,我们开始讨论卷积神经网络(convnet)的基础如何进行特征提取。我们了解了这个过程中的前两个操作是在带有 relu 激活的 Conv2D 层中进行的。 在这一课中,我们将看一下这个序列中的第三个(也是最后一个)操作:通过…