统计代码耗时

2023-11-16

二、常规方法

2.1 时间差统计

这种方式是最简单的方法,记录下开始时间,再记录下结束时间,计算时间差即可。

public class TimeDiffTest {
    public static void main(String[] args) throws InterruptedException {
        final long startMs = TimeUtils.nowMs();

        TimeUnit.SECONDS.sleep(5); // 模拟业务代码
    
        System.out.println("timeCost: " + TimeUtils.diffMs(startMs));
    }
}
/* output: 
timeCost: 5005
public class TimeUtils {
    /**
     * @return 当前毫秒数
     */
    public static long nowMs() {
        return System.currentTimeMillis();
    }

    /**
     * 当前毫秒与起始毫秒差
     * @param startMillis 开始纳秒数
     * @return 时间差
     */
    public static long diffMs(long startMillis) {
       return diffMs(startMillis, nowMs());
    }
}

这种方式的优点是实现简单,利于理解;缺点就是对代码的侵入性较大,看着很傻瓜,不优雅。

2.2 StopWatch

第二种方式是参考 StopWatch ,StopWatch 通常被用作统计代码耗时,各个框架和 Common 包都有自己的实现。

public class TraceWatchTest {
    public static void main(String[] args) throws InterruptedException {
        TraceWatch traceWatch = new TraceWatch();

        traceWatch.start("function1");
        TimeUnit.SECONDS.sleep(1); // 模拟业务代码
        traceWatch.stop();
    
        traceWatch.start("function2");
        TimeUnit.SECONDS.sleep(1); // 模拟业务代码
        traceWatch.stop();
    
        traceWatch.record("function1", 1); // 直接记录耗时
    
        System.out.println(JSON.toJSONString(traceWatch.getTaskMap()));
    }
}

/* output: 
{"function2":[{"data":1000,"taskName":"function2"}],"function1":[{"data":1000,"taskName":"function1"},{"data":1,"taskName":"function1"}]}
*/
public class TraceWatch {
    /** Start time of the current task. */
    private long startMs;

    /** Name of the current task. */
    @Nullable
    private String currentTaskName;
    
    @Getter
    private final Map<String, List<TaskInfo>> taskMap = new HashMap<>();
    
    /**
     * 开始时间差类型指标记录,如果需要终止,请调用 {@link #stop()}
     *
     * @param taskName 指标名
     */
    public void start(String taskName) throws IllegalStateException {
        if (this.currentTaskName != null) {
            throw new IllegalStateException("Can't start TraceWatch: it's already running");
        }
        this.currentTaskName = taskName;
        this.startMs = TimeUtils.nowMs();
    }
    
    /**
     * 终止时间差类型指标记录,调用前请确保已经调用
     */
    public void stop() throws IllegalStateException {
        if (this.currentTaskName == null) {
            throw new IllegalStateException("Can't stop TraceWatch: it's not running");
        }
        long lastTime = TimeUtils.nowMs() - this.startMs;
    
        TaskInfo info = new TaskInfo(this.currentTaskName, lastTime);
    
        this.taskMap.computeIfAbsent(this.currentTaskName, e -> new LinkedList<>()).add(info);
    
        this.currentTaskName = null;
    }
    
    /**
     * 直接记录指标数据,不局限于时间差类型
     *  @param taskName 指标名
     * @param data 指标数据
     */
    public void record(String taskName, Object data) {
        TaskInfo info = new TaskInfo(taskName, data);
    
        this.taskMap.computeIfAbsent(taskName, e -> new LinkedList<>()).add(info);
    }
    
    @Getter
    @AllArgsConstructor
    public static final class TaskInfo {
        private final String taskName;
    
        private final Object data;
    }
}

我是仿照 org.springframework.util.StopWatch 的实现,写了 TraceWatch 类,这个方法提供了两种耗时统计的方法:

1.通过调用 Start(name) 和 Stop() 方法,进行耗时统计。

2.通过调用 Record(name, timeCost),方法,直接记录耗时信息。

这种方式本质上和“时间差统计”是一致的,只是抽取了一层,稍微优雅了一点。

注:你可以根据自己的业务需要,自行修改 TraceWatch 内部的数据结构,我这里简单起见,内部的数据结构只是随便举了个例子。

三、高级方法

第二节提到的两种方法,用大白话来说都是“直来直去”的感觉,我们还可以尝试把代码写的更简便一点。

3.1 Function

在 jdk 1.8 中,引入了 java.util.function 包,通过该类提供的接口,能够实现在指定代码段的上下文执行额外代码的功能。

public class TraceHolderTest {
    public static void main(String[] args) {
        TraceWatch traceWatch = new TraceWatch();

        TraceHolder.run(traceWatch, "function1", i -> {
            try {
                TimeUnit.SECONDS.sleep(1); // 模拟业务代码
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    
        String result = TraceHolder.run(traceWatch, "function2", () -> {
            try {
                TimeUnit.SECONDS.sleep(1); // 模拟业务代码
                return "YES";
            } catch (InterruptedException e) {
                e.printStackTrace();
                return "NO";
            }
        });
    
        TraceHolder.run(traceWatch, "function1", i -> {
            try {
                TimeUnit.SECONDS.sleep(1); // 模拟业务代码
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    
        System.out.println(JSON.toJSONString(traceWatch.getTaskMap()));
    }
}

/* output: 
{"function2":[{"data":1004,"taskName":"function2"}],"function1":[{"data":1001,"taskName":"function1"},{"data":1002,"taskName":"function1"}]}
*/
public class TraceHolder {
    /**
     * 有返回值调用
     */
    public static <T> T run(TraceWatch traceWatch, String taskName, Supplier<T> supplier) {
        try {
            traceWatch.start(taskName);

            return supplier.get();
        } finally {
            traceWatch.stop();
        }
    }
    
    /**
     * 无返回值调用
     */
    public static void run(TraceWatch traceWatch, String taskName, IntConsumer function) {
        try {
            traceWatch.start(taskName);
    
            function.accept(0);
        } finally {
            traceWatch.stop();
        }
    }
}

这里我利用了 Supplier 和 IntConsumer 接口,对外提供了有返回值和无返回值得调用,在 TraceHolder 类中,在核心代码块的前后,分别调用了前文的 TraceWatch 的方法,实现了耗时统计的功能。

3.2 AutoCloseable

除了利用 Function 的特性,我们还可以使用 jdk 1.7 的 AutoCloseable 特性。说 AutoCloseable 可能有同学没听过,但是给大家展示下以下代码,就会立刻明白是什么东西了。

// 未使用 AutoCloseable
public static String readFirstLingFromFile(String path) throws IOException {
    BufferedReader br = null;
    try {
        br = new BufferedReader(new FileReader(path));
        return br.readLine();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (br != null) {
            br.close();
        }
    }
    return null;
}

// 使用 AutoCloseable
public static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

在 try 后方可以加载一个实现了 AutoCloseable 接口的对象,该对象作用于整个 try 语句块中,并且在执行完毕后回调 AutoCloseable#close() 方法。

让我们对 TraceWatch 类进行改造:

1.实现 AutoCloseable 接口,实现 close() 接口:

@Override
public void close() {
    this.stop();
}

修改 start() 方法,使其支持链式调用:

public TraceWatch start(String taskName) throws IllegalStateException {
    if (this.currentTaskName != null) {
        throw new IllegalStateException("Can't start TraceWatch: it's already running");
    }
    this.currentTaskName = taskName;
    this.startMs = TimeUtils.nowMs();
    
    return this;
}
public class AutoCloseableTest {
    public static void main(String[] args) {
        TraceWatch traceWatch = new TraceWatch();

        try(TraceWatch ignored = traceWatch.start("function1")) {
            try {
                TimeUnit.SECONDS.sleep(1); // 模拟业务代码
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        try(TraceWatch ignored = traceWatch.start("function2")) {
            try {
                TimeUnit.SECONDS.sleep(1); // 模拟业务代码
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        try(TraceWatch ignored = traceWatch.start("function1")) {
            try {
                TimeUnit.SECONDS.sleep(1); // 模拟业务代码
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        System.out.println(JSON.toJSONString(traceWatch.getTaskMap()));
    }
}

/* output: 
{"function2":[{"data":1001,"taskName":"function2"}],"function1":[{"data":1002,"taskName":"function1"},{"data":1002,"taskName":"function1"}]}
*/
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

统计代码耗时 的相关文章

  • 强化学习入门《Easy RL》

    什么是强化学习 强化学习关注的是智能体 Agent 在复杂的环境 Environment 中如何最大化获得的奖励 Reward 智能体和环境两部分组成了强化学习 在强化学习过程中 智能体与环境一直在交互 智能体在环境中获取某个状态后 它会利
  • python学习笔记#2元组和列表

    python学习笔记 2元组和列表 文章目录 python学习笔记 2元组和列表 前言 一 string包含引号 二 复杂数据类型 1 序列 2 tuple 元组 2 list 列表 总结 前言 学习python的复杂数据类型 tuple和
  • 以element ui为例分析前端各种弹窗和对话框的使用场景与区别

    文章目录 摘要 Dialog 对话框 Drawer 抽屉 Notice 通知 MessageBox 弹框 Popconfirm 气泡确认框 Message 消息提示 Notification 通知 Dialog 对话框与Drawer 抽屉的
  • MySQL中的锁机制详解

    概述 事务的隔离性 隔离级别 是由锁来保证的 并发访问数据的情况分为 1 读 读 即并发事务相继读取相同的记录 因为没涉及到数据的更改 所以不会有并发安全问题 允许这种情况发生 2 写 写 即并发事务对相同记录进行修改 会出现脏写问题 因为
  • python flask 网页适应手机端浏览器的编程方法

    1 使用flask在电脑端开发了一个论坛网址 想在手机端浏览看看 却发现根本装不下 并且导航栏元素还消失了 先看电脑端访问是正常的 而手机端导航条不见了 这是因为手机和电脑屏幕分辨率不同导致的 最简单的办法就是添加自适应宽度 并缩放页面 这
  • 异步(延时)逻辑难题,以及采用lua的解决方法

    在网游程序里混过一阵子的程序员大都知道 异步逻辑 是游戏逻辑里最容易失误的地方之一 刷钱 刷经验 不花钱得到道具 然后关服 回档 删号等等等等 其可能造成的危害不胜枚举 而且实际上银行系统之类的地方遇到这种问题就更有趣了 不同团队对此类问题
  • BUUCTF base 第三题Upload-Labs-Linux1比较省事的方法

    1 安装蚁剑 首先下载蚁剑 链接 https pan baidu com s 1O6Ty2Qmk7AVuY9QU CD9gQ fm lk0 提取码 1234 其次解压蚁剑 共两个文件需解压 在AntSword Loader中双击运行 gt
  • PCB线宽与通流量

    PCB通流能力的计算一直缺乏权威的技术方法 公式 经验丰富的Layout工程师依靠个人经验能作出较准确的判断 但是对于Layout新手 不可谓遇上一道难题 PCB的通流能力取决于以下因素 线宽 线厚 铜箔厚度 容许温升 大家都知道 PCB走
  • 基于Redis的Geo实现附近商铺搜索(含源码)

    微信公众号访问地址 基于Redis的Geo实现附近商铺搜索 含源码 推荐文章 1 springBoot对接kafka 批量 并发 异步获取消息 并动态 批量插入库表 2 SpringBoot用线程池ThreadPoolTaskExecuto
  • 复杂网络数据集下载地址

    1 斯坦福大学公开数据集 Stanford Large Network Dataset Collectionhttp snap stanford edu data 2 那慕尔大学公开数据集 Networks konect cc http k
  • Java1.8之HashMap底层链表变红黑树浅析

    HashMap底层链表变红黑树浅析 广为流传的错误结论 大O表示法 真正的原因 全文浏览约10分钟 从一个错误的结论分析到HashMap链表转化为红黑树的原因 读完对HashMap底层会有更深的理解 广为流传的错误结论 众所周知 Java1
  • 宏基服务器型号,宏基云服务器排名

    宏基云服务器排名 内容精选 换一换 磁盘增强型弹性云服务器自带高存储带宽和IOPS的本地盘 具有高存储IOPS以及读写带宽的优势 同时 本地盘的价格更加低廉 在海量数据存储场景下 具备更高的性价比 磁盘增强型弹性云服务器具备如下特点 本地磁
  • 在multisim14上完成数码管的显示(0-9)

    提前说说 前几天给西电的同学做了一个小的线上课程设计 用到数码管 没想到我们课程设计也是关于数码管 所以在这总结一下如何仿真实现数码管 目标 完成一个数码管的显示 从0 9分别显示 一 首先 确定使用的是共阴极数码管 在元器库中找到 二 接
  • python 二叉树,先序回溯,层序队列,队列基础用法,二叉树深度

    文章目录 1 创建二叉树 先 中 后遍历 2 n个节点有多少种二叉树 递归 3 层序遍历 4 队列基础用法 五 二叉树深度 1 创建二叉树 先 中 后遍历 创建二叉树 class TreeNode def init self data le
  • Java学习路线及步骤详解

    导言 Java是一门广泛应用于软件开发和互联网领域的编程语言 在国内外都具有广泛的应用和需求 对于想要学习Java的初学者来说 了解一个清晰的学习路线是非常重要的 它可以帮助你更好地规划学习进程 逐步提升自己的技能和能力 本篇博客将为你详细
  • k8s安装遇到过的一些问题

    无法获取recomended yaml文件 root k8master1 wget https raw githubusercontent com kubernetes dashboard v2 7 0 aio deploy recomme
  • python 之 web3 与智能合约的交互、编译等使用

    一 背景 web3 py是一个用于与以太坊交互的 Python 库 它常见于去中心化应用程序 dapps 中 帮助发送交易 与智能合约交互 读取块数据以及各种其他用例 最初的 API 源自Web3 js Javascript API 但后来
  • python-流行病学调查报告内容提取、梳理

    在各类传染病疫情应急处理过程中 快速 准确 高效的抓取流调报告中的相关内容 分析接触关系 是各项防控措施制定的理论基础 在参与的疫情防控中 现场流调人员会收集感染者 密接者的流行病学信息 反馈到疫情指挥中心后由相关人员汇总 整理和分析 在整
  • ioctl应用详解

    前言 参考以下资料 linux 内核 ioctl 函数详解 https blog csdn net qq 19923217 article details 82698787 Linux设备驱动之Ioctl控制 https www cnblo
  • pytorch--matmul、mm和bmm的区别

    pytorch中matmul和mm和bmm区别 matmul mm bmm 结论 matmul mm bmm 顾名思义 就是两个batch矩阵乘法 结论 从官方文档可以看出 mm只能进行矩阵乘法 也就是输入的两个tensor维度只能是 b

随机推荐

  • 当单例模式遇到序列化会出现什么问题

    什么是单例模式 这种模式涉及到一个单一的类 该类负责创建自己的对象 同时确保只有单个对象被创建 这个类提供了一种访问其唯一的对象的方式 可以直接访问 不需要实例化该类的对象 什么是序列化 简单来说序列化就是一种用来处理对象流的机制 所谓对象
  • 【Spark NLP】第 3 章:Apache Spark 上的 NLP

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • torch 正确的测试模型推理时间 torch.cuda.synchronize()

    个人简介 深度学习图像领域工作者 总结链接 链接中主要是个人工作的总结 每个链接都是一些常用demo 代码直接复制运行即可 包括 1 工作中常用深度学习脚本 2 torch numpy等常用函数详解 3 opencv 图片 视频等操作 4
  • 关于pytorch网络模型可视化函数make_dot的一些问题

    关于pytorch网络模型可视化函数make dot的一些问题 首先 放上make dot函数的源码 实验室同门给的 出处不详 def make dot var params None 画出 PyTorch 自动梯度图 autograd g
  • 半导体工艺流程

    本文首发 公众号 半导体产业园 转载链接 https www sohu com a 257666855 100269991 spm smpc content share 1 16073320927520q75qyB comment area
  • Java 简历 专业技能可以这样写

    关于Java的专业技能可以写 1 熟练掌握Java语言以及面向对象设计思想 具有扎实的Java编程功底和编码规范 2 熟练使用Spring SpringMVC MyBatis MyBatis Plus tkmybatis Spring bo
  • Java高并发秒杀系统(二)

    版权声明 本文为博主原创文章 未经博主允许不得转载 https blog csdn net GallenZhang article details 78626730 秒杀系优化分析 1 详情页面 2系统时间 3地址暴露接口 4执行秒杀操作
  • 手把手教你如何快速搭建个人博客

    之前有录制和编写过WordPress搭建个人博客的内容 但是都比较麻烦 需要在控制台黑框复制运行相关的命令 很多没接触过过的用户还是有一定的困难 那么今天就把最最最简单的方法分享给大家 全程都是可视化的操作 不需要在复制相关的命令了 赶快跟
  • GitHub上精确搜索查找项目笔记

    1 通过in关键词限制搜索范围 1 abc in name 项目名里面包含abc 2 abc in description 项目描述包含abc 3 abc in readme 项目的readme文件里包含abc 4 还可以通过abc in
  • Error: failed to download “stable/openebs“

    安装openebs出现下面的异常 Error failed to download stable openebs hint running helm repo update may help 解决方案 未修改前的helm repo源 修改h
  • 解决在 Win7 旗舰版虚拟机中安装 VMware Tools 失败问题

    报错提示如下 安装程序无法自动安装Virtual Machine Communication Interface VMCI 驱动程序 必须手动安装此驱动程序 解决方法 安装以下两个补丁 1 kb4474419 2 kb4490628 按顺序
  • android 调用短信,Android实现接收短信和发送短信功能

    在学接收短信和发送短信之前 先简单介绍一下 SMS 短消息服务 SMS Short Message Service 短信息服务 是一种存储和转发服务 也就是说 短信息并不是直接从发信人发送到接收人 而是始终通过 SMS 中心进行转发 如果接
  • linux运行rs程序,【linux-基础】安装scp,rz,rs命令

    在测试中需要在两台虚拟机之间传递文件 首先想到的是scp命令 结果提示 bash scp command not found 想当然用yum install scp命令安装 结果提示 No package scp available 后来发
  • WebDriver概述

    什么是WebDriver Webdriver Selenium2 0 是一种用于Web应用程序的自动测试工具 它提供了一套友好的API Webdriver完全就是一套类库 不依赖于任何测试框架 除了必要的浏览器驱动 WebDriver AP
  • 用Python画奥运五环

    最近接触到了Python的一个有趣的库turtle 写了一个画奥运五环的程序 代码如下 用turtle模块绘画奥运五环 import turtle 设置公共属性 turtle width 10 第一个环 turtle color black
  • 华为OD机试 - 最大社交距离(Java)

    题目描述 疫情期间需要大家保证一定的社交距离 公司组织开交流会议 座位一排共 N 个座位 编号分别为 0 N 1 要求员工一个接着一个进入会议室 并且可以在任何时候离开会议室 满足 每当一个员工进入时 需要坐到最大社交距离 最大化自己和其他
  • IOS开发笔记之常用的第三方库(太多了。)

    图像 1 图片浏览控件MWPhotoBrowser 实现了一个照片浏览器类似 iOS 自带的相册应用 可显示来自手机的图片或者是网络图片 可自动从网络下载图片并进行缓存 可对图片进行缩放等操作 下载 https github com mwa
  • js-- 1-100循环

  • Linux系统中运行.sh文件的几种方法

    在Linux系统中执行 sh文件的几种方法 1 cd到 sh文件所在的目录 然后执行 xxx sh 前提 该 sh文件要有可执行的权限 chmod u x xxx sh 2 在任何路径下 输入 sh文件的绝对路径进行执行 前提 该 sh文件
  • 统计代码耗时

    二 常规方法 2 1 时间差统计 这种方式是最简单的方法 记录下开始时间 再记录下结束时间 计算时间差即可 public class TimeDiffTest public static void main String args thro