为什么第一次运行总是慢很多?

2023-11-30

我编写了一个宏来报告运行给定操作所需的时间。它运行多次并打印出每次运行的时间(以纳秒为单位)。第一次运行总是比后续运行花费更多的时间。为什么会这样?

这是 10 x 10 次运行的结果,计时Thread.yield():

> (dotimes [x 10] (prn (times 10 (Thread/yield))))

[55395 1659 622 561 591 702 795 719 742 624]
[3255 772 884 677 787 634 605 664 629 657]
[3431 789 965 671 774 767 627 627 521 717]
[2653 780 619 632 616 614 606 602 629 667]
[2373 759 700 676 557 639 659 654 659 676]
[2884 929 627 604 689 614 614 666 588 596]
[2796 749 672 769 667 852 629 589 627 802]
[1308 514 395 321 352 345 411 339 436 315]
[1390 363 328 337 330 321 324 347 333 342]
[1461 416 410 320 414 381 380 388 388 396]

第一批的第一次运行非常慢,我猜这是因为 JIT 第一次看到代码 - 这很公平。但所有后续批次中的第一次运行也明显慢于后续运行。为什么?

代码为times macro:

(defmacro time
  [expr]
  `(let [t1# (System/nanoTime)]
     ~expr 
     (- (System/nanoTime) t1#)))

(defmacro times
  [reps expr]
  `(loop [reps# ~reps times# []]
     (if (zero? reps#) 
       times#
       (recur (dec reps#) (conj times# (time ~expr))))))

反编译产生以下结果,所以System.nanoTime()好像是前后直接调用的Thread.yield(), 如预期:

> (decompile (dotimes [x 10] (prn (times 10 (Thread/yield)))))

...

public Object invoke() {
    long reps__1952__auto__2355 = 10L;
    Object times__1953__auto__2356 = PersistentVector.EMPTY;
    while (reps__1952__auto__2355 != 0L) {
        final long dec = Numbers.dec(reps__1952__auto__2355);
        final IFn fn = (IFn)const__3.getRawRoot();
        final Object o = times__1953__auto__2356;
        times__1953__auto__2356 = null;
        final long t1__1946__auto__2354 = System.nanoTime();
        Thread.yield();
        times__1953__auto__2356 = fn.invoke(o, Numbers.num(Numbers.minus(System.nanoTime(), t1__1946__auto__2354)));
        reps__1952__auto__2355 = dec;
    }
    final Object o2 = times__1953__auto__2356;
    times__1953__auto__2356 = null;
    return o2;
}

第一次运行总是比后续运行花费更多的时间。为什么会这样?

基准测试结果中还有另一个棘手的依赖因素:I/O。尝试一些测试运行return时序向量而不是print他们,你应该看到与此更相符的结果:

(for [_ (range 10)]
  (times 10 (Thread/yield)))
=>
([32674 1539 1068 1063 1027 1026 1025 1031 1034 1035]
 [1335 1048 1030 1036 1043 1037 1036 1031 1034 1047]
 [1088 1043 1029 1035 1045 1035 1036 1035 1045 1047]
 [1051 1037 1032 1031 1048 1045 1039 1045 1042 1037]
 [1054 1048 1032 1036 1046 1029 1038 1038 1039 1051]
 [1050 1051 1039 1037 1038 1035 1030 1030 1045 1031]
 [1054 1045 1034 1034 1045 1037 1037 1035 1046 1044]
 [1051 1041 1032 1050 1061 1039 1045 1041 1057 1034]
 [1052 1042 1034 1032 1035 1045 1043 1038 1052 1052]
 [1053 1053 1041 1043 1053 1044 1039 1042 1051 1038])

如果你使用System.out.println在你的基准测试中而不是prn,您应该看到相同的减速行为,但不那么夸张:

(dotimes [x 10]
  (.println System/out (times 10 (Thread/yield))))
=> nil
[33521 1733 1232 1161 1150 1135 1151 1138 1143 1144]
[1724 1205 1149 1152 1141 1149 1149 1150 1139 1145]
[1368 1156 1141 1139 1147 1149 1141 1147 1141 1149]
[1306 1159 1150 1141 1150 1148 1147 1142 1144 1149]
[1329 1161 1155 1144 1140 1155 1151 1149 1149 1140]
[1319 1154 1140 1143 1147 1154 1156 1149 1148 1145]
[1291 1166 1164 1149 1140 1150 1140 1152 1141 1139]
[4482 1194 1148 1150 1137 1165 1163 1154 1149 1152]
[1333 1184 1162 1163 1138 1149 1150 1151 1137 1145]
[1318 1150 1144 1150 1151 1147 1138 1147 1143 1149]
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么第一次运行总是慢很多? 的相关文章

  • eclipse juno 打开时出错

    在安装 Eclipse 并正常工作一年多后 我今天打开 Eclipse Juno 并在打开工作区时收到一条错误消息 我使用的是 Windows 8 64 位 Java 64 位和 Eclipse 64 位 此后我尝试重新安装 Java 和
  • 如何用Java创建图像

    比如说在我的程序中 我有这个paint 方法 我的愿望是创建所绘制的矩形的图像 使用 for 循环 我尝试了下面的方法 它确实给了我那些矩形 蓝色 但背景是全黑的 当我运行程序而不创建图像 仅在 JFrame 上绘制矩形时 背景为白色 我怎
  • 如何在流中收集到TreeMap中?

    我有两个Collectors groupingBy在流中 我需要收集所有信息TreeMap 我的代码 Map
  • 使用 Gson 序列化时如何公开类名

    我的场景非常复杂 但总结如下 我试图了解编译器的源代码 并了解每个 AST 节点代表什么 我正在生成不同程序的 AST 的 JSON 序列化 然后检查可视化的 JSON 输出 它工作得很好 除了一个问题是在 Gson 中生成的 JSON 数
  • Jackson Json 将对象反序列化为列表

    我正在使用 Spring 的 Web 服务RestTemplate并反序列化Jackson 在来自服务器的 JSON 响应中 其中一个字段可以是对象或列表 这意味着它可以是 result or result 有没有办法通过对我要反序列化的类
  • 包含小时、分钟和秒的周期[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我需要一个代表年 月 周 日 小时 分钟 秒的间隔数据类型 前三年 年 月 日 可以用Period最后
  • 无法解析配置“:app:debugRuntimeClasspath”的所有文件。问题

    我的 android studio 遇到了下一个问题 导致 org gradle api internal artifacts ivyservice DefaultLenientConfiguration ArtifactResolveEx
  • 如何使用 Spring Security 跨多个基于 JVM 的应用程序实现单点登录

    我目前正在尝试跨多个基于 JVM Grails Servlet 的 Web 应用程序实现单点登录解决方案 这些应用程序目前都部署在同一个 servlet 容器 当前是 Tomcat 但不想将我的解决方案仅限于 Tomcat 中 所有 Web
  • 文件保存在文件系统中 VS 保存在数据库中

    我正在设计一个 servlet 或 Struts2 中的操作 用于文件 图像 文档等 下载 但我想知道哪种更好的方法可以将文件保留在文件系统和数据库中 只需保留文件的路径或将文件保留在数据库中 如 BLOB 我知道当我查询数据库时 哪里的
  • 在 Java 5 及更高版本中迭代 java.util.Map 的所有键/值对的最简单方法是什么?

    在 Java 5 及更高版本中迭代 java util Map 的所有键 值对的最简单方法是什么 假设K是您的密钥类型 并且V是你的值类型 for Map Entry
  • 在 JSON 对象中强制执行非空字段

    我们的 REST API 接收一些 JSON 对象输入 其中某些字段要求不为空 这些可以是字符串 整数 甚至可以是其他一些类实例作为参考 我们正在尝试找到一种方法来强制这些字段不为空 而不是在 API 中进行空检查的正确方法 当前的 if
  • 如何将 currentTimeMillis 转换为可读的日期格式? [复制]

    这个问题在这里已经有答案了 我想用currentTimeMillis两次 这样我就可以计算持续时间 但我也想以用户可读的格式显示时间和日期 我遇到了麻烦currentTimeMillis有利于计算 但我看不到内置函数可以转换为合适的时间或时
  • 日志记录在 Android 设备上实际上有什么作用?

    我一直在 Android 示例中看到这样的代码 try catch Exception e Log e Error e getMessage 什么是Log e实际上在物理设备上做什么 它进入系统日志 开发人员可以通过 SDK 工具访问该日志
  • Spring Boot如何加入自定义查询

    我需要创建一个端点 该端点按州返回人口普查数据以及城市列表 我目前使用两个端点来获取此数据 目前回应 自定义查询一 censusByState id 1 code 11 name Rond nia statePopulation 18152
  • 为什么 HttpServletRequest 输入流为空?

    我有这段代码 我从请求输入流读取输入并使用 JacksonMapper 转换为 POJO 它在具有 guice 支持的 jetty 7 容器中运行 Override protected void doPost HttpServletRequ
  • Maven `help: effective-pom` 只为单个项目生成,而不是所有项目

    我想为多模块构建中的所有子项目生成有效的 pom The help effective pom文档here http maven apache org plugins maven help plugin usage html The hel
  • 如何确保超类的子类方法的线程安全?

    我参加了一次面试 并被要求为以下要求设计一个课程 假设我有一个 A 类 它可以有任意数量的子类 即子类 类 A 有一个名为 doSomething 的方法 该方法是同步的 要求是 A 的所有子类都是强制性的重写 doSomething me
  • 如果所有类不在同一个包中,Spring @autowired 不起作用

    我有四个包裹 com spring org Files HomeController java com spring org dao Files SubscriberDao java SubscriberDaoImpl java com s
  • javafx中的stackpane和root有什么区别?

    我正在练习javafx做饼图 以下是开发饼图的代码 如果我这样做Group并与StackPane 我发现输出没有区别 我已经评论了组部分 只是徘徊两者之间的区别 import javafx application Application i
  • 在Java的System.out中以表格格式输出

    我正在从数据库获取结果 并希望将数据作为 Java 标准输出中的表输出 我尝试过使用 t 但我想要的第一列的长度变化很大 有没有办法将其显示在类似输出的漂亮表格中 Use System out format http java sun co

随机推荐