• Java计算代码段的运行时间


    前言

    在日常开发功能时,同一种功能可能会有多种实现方式。我们需要做一个取舍。
    最常见的条件就是性能、可读性、可维护性。

    本篇文章,我们主要讨论“性能”。

    场景

    假设我们现在需要计算一段代码的运行时间。
    最常见的写法是,在执行这段代码前,获得一下当前的时间戳,在执行这段代码后,获取一下当前的时间戳,然后俩时间相减,就是花费时间了。

    但有时,我们需要将这段代码执行多次。
    这种场景是,执行的时间戳很小,没有可比性。比如执行一段代码,运行时间是 0 或者 2毫秒。

    这种时候你可能会说,那就用一个for循环,执行多次,计算平均时间就好了。
    问题来了,如果这种相似的操作,写的多了呢,用的地方很多呢?

    我们现在就需要将它给写成一套模板,只需要简单的填充参数,调用,就能实现上述的功能。

    代码实现

    MethodBody 接口定义

    这个接口主要是用于填充代码段,因此设计为函数式接口,方便调用。

    package org.feng.calc;
    
    /**
     * 运行的方法内容:使用Lambda
     *
     * @version V1.0
     * @author: fengjinsong
     * @date: 2022年11月15日 19时56分
     */
    @FunctionalInterface
    public interface MethodBody {
        void run();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    CalcExecuteTimeResult 运行结果实体

    package org.feng.calc;
    
    import lombok.Data;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * 计算执行时间的结果保存
     *
     * @version V1.0
     * @author: fengjinsong
     * @date: 2022年11月15日 18时59分
     */
    @Data
    public class CalcExecuteTimeResult {
        /**
         * 执行代码花费的时间
         */
        private List<Long> costTime;
    
        public CalcExecuteTimeResult(int size) {
            costTime = new ArrayList<>(size);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    ExecuteTemplate 执行模板定义

    package org.feng.calc;
    
    import lombok.Getter;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 执行模板
     *
     * @version V1.0
     * @author: fengjinsong
     * @date: 2022年11月15日 19时58分
     */
    public class ExecuteTemplate {
        private final List<MethodBody> methodBodyList;
        @Getter
        private CalcExecuteTimeResult calcExecuteTimeResult;
    
        public ExecuteTemplate() {
            this.methodBodyList = new ArrayList<>();
        }
    
        public void addMethod(MethodBody methodBody) {
            methodBodyList.add(methodBody);
        }
    
        /**
         * 执行
         *
         * @param timeUnit  时间单位
         * @param frequency 频次-单个方法{@link MethodBody}实例执行的次数
         */
        void process(TimeUnit timeUnit, long frequency) {
            this.calcExecuteTimeResult = new CalcExecuteTimeResult(methodBodyList.size());
            List<Long> costTime = calcExecuteTimeResult.getCostTime();
            for (MethodBody methodBody : methodBodyList) {
                long startTime = getTime(timeUnit);
                for (int i = 0; i < frequency; i++) {
                    methodBody.run();
                }
                long endTime = getTime(timeUnit);
                costTime.add(endTime - startTime);
            }
        }
    
        private long getTime(TimeUnit timeUnit) {
            if (!SUPPORTED_TIME_UNIT.contains(timeUnit)) {
                throw new UnsupportedOperationException("不支持的时间单位:" + timeUnit);
            }
    
            if (TimeUnit.NANOSECONDS.equals(timeUnit)) {
                return System.nanoTime();
            }
            return System.currentTimeMillis();
        }
    
        /**
         * 当前支持的时间单位
         */
        private static final Set<TimeUnit> SUPPORTED_TIME_UNIT = Set.of(TimeUnit.MILLISECONDS, TimeUnit.NANOSECONDS);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    CalcExecuteTimeContext 计算执行时间上下文

    package org.feng.calc;
    
    import lombok.Setter;
    import lombok.experimental.Accessors;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * 计算执行时间-上下文
     *
     * @version V1.0
     * @author: fengjinsong
     * @date: 2022年11月15日 19时51分
     */
    @Setter
    @Accessors(chain = true)
    public class CalcExecuteTimeContext {
    
        private TimeUnit timeUnit;
        private Long frequency;
        private ExecuteTemplate executeTemplate;
    
        public CalcExecuteTimeResult run() {
            executeTemplate.process(timeUnit, frequency);
            return executeTemplate.getCalcExecuteTimeResult();
        }
    
        public void addMethod(MethodBody methodBody){
            executeTemplate.addMethod(methodBody);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    测试运行

    package org.feng.calc;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * 测试运行
     *
     * @version v1.0
     * @author: fengjinsong
     * @date: 2022年11月15日 21时03分
     */
    public class Client {
        public static void main(String[] args) {
            // 初始化上下文:设置每个方法执行的次数,以及计算时间时使用的时间单位,执行模板
            CalcExecuteTimeContext context = new CalcExecuteTimeContext()
                    .setFrequency(2L)
                    .setTimeUnit(TimeUnit.MILLISECONDS)
                    .setExecuteTemplate(new ExecuteTemplate());
    
            context.addMethod(() -> {
                System.out.println(111);
                System.out.println(111);
                System.out.println(111);
                System.out.println(111);
                System.out.println(111);
            });
    
            context.addMethod(() -> {
                System.out.println(222);
                System.out.println(222);
                System.out.println(222);
                System.out.println(222);
                System.out.println(222);
            });
    
            // 计算得到方法运行的结果
            CalcExecuteTimeResult executeTimeResult = context.run();
            System.out.println(executeTimeResult);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    运行结果:

    111
    111
    111
    111
    111
    111
    111
    111
    111
    111
    222
    222
    222
    222
    222
    222
    222
    222
    222
    222
    CalcExecuteTimeResult(costTime=[0, 1])
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
  • 相关阅读:
    【重要】C语言进阶 -- 自定义类型:结构体、枚举、联合
    有效括号相关
    mysql高阶sql语句
    neo4j数据库导出
    Pr:创建自己的项目模板
    【PAT B-1038】统计同成绩学生
    VUE [入门篇]
    Elasticsearch基于snapshot进行云上备份
    25-数据结构-稀疏矩阵-三元组
    光伏发电系统最大功率跟踪控制MATLAB仿真模型(电导增量法+扰动观察法)
  • 原文地址:https://blog.csdn.net/FBB360JAVA/article/details/127874276