- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我试图编写一个相当通用的测试框架来分析一组函数,但遇到了一个我无法在下面详细说明的问题。
这个概念很简单。我创建了一个 Test
抽象类:
public abstract class Test {
private final String name;
public Test(String name) {
this.name = name;
}
public abstract void test();
}
然后,我有一个主测试类,其中包含一些配置信息和运行测试的循环。
public class MyTestClass {
public static double staticMethod1(Quat4f q) {
double angle;
float dirW = q.w;
if (q.w * q.w + q.y * q.y > 0.0f) {
if (q.w > 0.f && q.y < 0.0f)
dirW *= -1.0f;
angle = 2.0f * Math.acos(dirW);
} else {
angle = 0.0f;
}
return angle / 6.283f * 100.f;
}
public static double staticMethod2(Quat4f q) {
AxisAngle4f axisAngle = new AxisAngle4f();
axisAngle.set(q);
return axisAngle.angle / 6.283f * 100.f;
}
public static final void main(String[] args) {
final Quat4f quaternion = new Quat4f(0, 0, 0, 1);
Test[] tests = new Test[] {
new Test("staticMethod1") {
@Override
public void test() {
staticMethod1(quaternion);
}
},
new Test("staticMethod2") {
@Override
public void test() {
staticMethod2(quaternion);
}
}
};
long startTime = 0;
int repeat = 10; //How many times to repeat each iteration.
int[] tiers = new int[] { 1000, 10000, 100000, 1000000 };
long[][][] times = new long[tests.length][tiers.length][iterations];
for (int testIndex = 0; testIndex < tests.length; testIndex++) {
for (int tierIndex = 0; tierIndex < tiers.length; tierIndex++) {
for (int r = 0; r < repeat; r++) {
startTime = System.nanoTime();
for (int i = 0; i < tiers[tierIndex]; i++) {
tests[testIndex].run(); //run the test
}
times[testIndex][tierIndex][r] = System.nanoTime() - startTime; //Stash the execution time in the array.
}
}
}
}
}
看到这段代码,您可能想知道为什么 Test.run()
方法调用静态方法。那是因为最初我只是将对静态方法的硬编码调用嵌入到循环中。而不是调用 tests[testIndex].run()
我会在那里显式调用 staticMethod1(quaternion)
。这也意味着为每个方法冗余地复制此循环代码 - 这导致我创建抽象基类,以便我基本上可以创建一个回调数组来测试。
因此,在切换到使用回调 Test
类之后,我没有显式调用静态函数,而是观察到两件事:
这是我显式调用静态方法时的输出表(所有时间都以纳秒为单位):
1000 10000 100000 1000000
staticMethod1
315358 424208 1451141 14495864
125334 410525 1483797 14657896
125956 412079 1445543 14702681
150837 413012 1473845 14677179
126578 412080 1419419 14415313
126268 413323 1450830 14600361
125645 411457 1437147 14504261
126889 414257 1431548 14402563
129689 420476 1476954 14548734
848417 425453 1471046 14409715
staticMethod2
1528581 1031287 3137712 2180755
228899 303540 218947 2227406
228276 303228 218324 2232071
235118 301362 218324 2174224
226411 317534 218636 2180133
226410 302918 218946 2143434
253779 302606 219879 2116689
226099 349257 219880 2108913
240717 303228 218946 2150899
250358 303228 218946 2159607
这里是相同的代码,只是从我的抽象基础 Test
类中执行:
1000 10000 100000 1000000
staticMethod1
360453 454686 1985445 15699447
155191 449400 1639298 15048205
152391 449089 1576165 15128134
175095 451888 1537289 15300429
156746 466816 1600734 15190645
157989 464950 1641476 15483610
157368 452198 1559681 15316290
157990 460285 1572122 15402439
157367 527773 1538222 15078995
878274 454065 1548485 15077439
staticMethod2
1519562 1101263 1674130 8842756
274616 335883 1481309 8728930
285190 339616 1471046 8842135
291721 334950 1280089 8591155
294831 347391 1339491 13402065
332152 343970 1299683 10950426
300429 326553 1252100 7778814
285190 324999 1365615 8569385
297008 341792 1284133 7734030
283324 326554 1327984 11505256
我能形成的唯一猜想是,这可能与 Java 堆栈框架概念有关。我真的很想找人深入分析为什么会发生这种情况。
这些截然不同的结果可能是什么结果?
我在家里的电脑上重新运行了测试,所以我想我会重新发布这些结果以确保准确性。
1000 10000 100000 1000000
staticMethod1
629020 688864 3016204 40796517
348542 589891 2662401 39673949
355447 611921 3559403 39613447
416936 617511 4022701 39335929
412660 635267 4290355 38862108
409702 751996 4055583 38823967
405426 761202 4063803 38998238
410030 760545 4024016 39131407
411346 656640 3877366 38737489
1794991 723060 4139759 38286028
staticMethod2
2219818 4198617 2526272 15647236
735555 1939011 2651879 14482251
761860 445542 2480238 12990096
734569 222607 2437822 14278058
734898 264366 2323394 23561771
743118 220633 2739672 15669266
746734 224909 5159080 12916113
781918 223593 2342794 14843616
789481 229512 2740658 13400784
865108 227210 5202155 22015033
1000 10000 100000 1000000
staticMethod2
2159974 1598690 4343951 4011522
755284 484013 4646131 3989491
779945 460667 390302 4114111
866752 469874 413318 3833963
911141 495193 433376 4024016
878918 468230 424827 4162118
892070 452447 431074 3830346
806579 419894 463298 4003301
814142 424169 424826 3961871
830253 417593 432718 3823112
staticMethod1
768437 632637 4596480 38401771
421539 655325 3811603 37536663
418579 657626 3917481 37377517
425813 648091 3887230 37347924
423512 653023 3800095 38334692
428772 570820 3810288 37640568
435020 581013 3795162 37543896
426800 578382 3805027 37390670
448830 567861 4004617 37502466
1883443 663874 3848101 38096961
使用 AxisAngle4f 的单个实例化的回调(staticMethod1、staticMethod2)
1000 10000 100000 1000000
staticMethod1
693138 745420 4382752 26091003
405098 677355 3378227 41866476
390630 669793 4349213 42472807
430088 699057 4296931 27899147
385697 675711 4300549 42643790
382410 658941 4296603 32330563
393918 662888 2602557 42622417
380437 666833 2588747 32903026
393918 738515 2616367 26079823
1805843 679985 2570004 42191343
staticMethod2
444556 1640449 963422 8620168
463298 464942 946325 8545856
431732 474478 877931 8645487
452776 466915 870698 8761229
432718 449487 882534 8572490
443898 464613 876288 8482066
414633 538596 871684 8672121
408715 190054 876287 8626744
405427 96342 874643 8607016
436664 96343 847681 8543883
最佳答案
这些结果并不是真正的“戏剧性”。 1000000 次运行的平均值为:
事实上,它们之间的减速相差(几乎正好)一个数量级是很奇怪的,但重要的是回调方法最多减慢了大约 7 ns。这还不算太多。
您发布的更多结果,测试顺序为method2
然后method1
,符合以下内容:
Test
类的相同实现;单态站点的速度优势既在于避免虚函数表查找,又在于允许方法内联发生。您的两种方法都非常简短,适合内联。
你可以进一步验证这种重新编译发生一次,但只有一次,通过在你从一个切换时使用 --XX:+PrintCompilation
结合 println
测试另一个。
您应该避免您的时间安排受到 JVM 的这种复杂性的影响。为此,使用 test(int iterations)
方法并将最内层的循环插入其中。这将使关键方法调度每至少 1,000 次迭代仅发生一次,并且变得无关紧要;
不相信任何低于 1 毫秒的时间测量值。 System.nanoTime
的精度远不及 1 ns:它的粒度通常在 1 µs 左右,要获得良好的精度,您必须远高于此。
关于从回调类执行代码时,Java 性能测试会发生变化。 Java堆栈框架问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18540309/
SQLite、Content provider 和 Shared Preference 之间的所有已知区别。 但我想知道什么时候需要根据情况使用 SQLite 或 Content Provider 或
警告:我正在使用一个我无法完全控制的后端,所以我正在努力解决 Backbone 中的一些注意事项,这些注意事项可能在其他地方更好地解决......不幸的是,我别无选择,只能在这里处理它们! 所以,我的
我一整天都在挣扎。我的预输入搜索表达式与远程 json 数据完美配合。但是当我尝试使用相同的 json 数据作为预取数据时,建议为空。点击第一个标志后,我收到预定义消息“无法找到任何内容...”,结果
我正在制作一个模拟 NHL 选秀彩票的程序,其中屏幕右侧应该有一个 JTextField,并且在左侧绘制弹跳的选秀球。我创建了一个名为 Ball 的类,它实现了 Runnable,并在我的主 Draf
这个问题已经有答案了: How can I calculate a time span in Java and format the output? (18 个回答) 已关闭 9 年前。 这是我的代码
我有一个 ASP.NET Web API 应用程序在我的本地 IIS 实例上运行。 Web 应用程序配置有 CORS。我调用的 Web API 方法类似于: [POST("/API/{foo}/{ba
我将用户输入的时间和日期作为: DatePicker dp = (DatePicker) findViewById(R.id.datePicker); TimePicker tp = (TimePic
放宽“邻居”的标准是否足够,或者是否有其他标准行动可以采取? 最佳答案 如果所有相邻解决方案都是 Tabu,则听起来您的 Tabu 列表的大小太长或您的释放策略太严格。一个好的 Tabu 列表长度是
我正在阅读来自 cppreference 的代码示例: #include #include #include #include template void print_queue(T& q)
我快疯了,我试图理解工具提示的行为,但没有成功。 1. 第一个问题是当我尝试通过插件(按钮 1)在点击事件中使用它时 -> 如果您转到 Fiddle,您会在“内容”内看到该函数' 每次点击都会调用该属
我在功能组件中有以下代码: const [ folder, setFolder ] = useState([]); const folderData = useContext(FolderContex
我在使用预签名网址和 AFNetworking 3.0 从 S3 获取图像时遇到问题。我可以使用 NSMutableURLRequest 和 NSURLSession 获取图像,但是当我使用 AFHT
我正在使用 Oracle ojdbc 12 和 Java 8 处理 Oracle UCP 管理器的问题。当 UCP 池启动失败时,我希望关闭它创建的连接。 当池初始化期间遇到 ORA-02391:超过
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve
引用这个plunker: https://plnkr.co/edit/GWsbdDWVvBYNMqyxzlLY?p=preview 我在 styles.css 文件和 src/app.ts 文件中指定
为什么我的条形这么细?我尝试将宽度设置为 1,它们变得非常厚。我不知道还能尝试什么。默认厚度为 0.8,这是应该的样子吗? import matplotlib.pyplot as plt import
当我编写时,查询按预期执行: SELECT id, day2.count - day1.count AS diff FROM day1 NATURAL JOIN day2; 但我真正想要的是右连接。当
我有以下时间数据: 0 08/01/16 13:07:46,335437 1 18/02/16 08:40:40,565575 2 14/01/16 22:2
一些背景知识 -我的 NodeJS 服务器在端口 3001 上运行,我的 React 应用程序在端口 3000 上运行。我在 React 应用程序 package.json 中设置了一个代理来代理对端
我面临着一个愚蠢的问题。我试图在我的 Angular 应用程序中延迟加载我的图像,我已经尝试过这个2: 但是他们都设置了 src attr 而不是 data-src,我在这里遗漏了什么吗?保留 d
我是一名优秀的程序员,十分优秀!