我必须报告java方法的平均运行时间。我是按照以下方式做的
//method start
long startTime = System.nanoTime();
//method body here ...
long estimationTime = System.nanoTime() - startTime;
//method end
我多次运行该方法,记录结果,然后以微秒为单位报告运行时间的均值和方差。
这是问题我得到了以下值(存在非常大的峰值)
请注意,其他值不是零(放大显示它)
我的问题:
看一下方法体(对于好奇的)
TraceRecord resultRecord = new TraceRecord();
resultRecord.setTimeStamp(timeStamp);
resultRecord.setUserID(userID);
if (sensorValue.getSensorType() == SensorType.WIFI) {
ArrayList<WifiBaseStation> wifiAPsInRange = new ArrayList<WifiBaseStation>();
for (int i = 0; i < sensorValue.getBaseStationsIdentifiers().length; i++) {
WifiBaseStation wifiAP = new WifiBaseStation(sensorValue.getRepresentativeName(i),
sensorValue.getBaseStationsIdentifier(i));
wifiAP.getSignalStrengthsList().add(sensorValue.getSignalValue(i));
wifiAPsInRange.add(wifiAP);
}
if (wifiAPsInRange.size() > 0) {
double averageLong = 0;
double averageLat = 0;
int matchedCount = 0;
for (WifiBaseStation bs : wifiAPsInRange) {
WifiBaseStation bsFromTable = WiFiUniqueWarDrivingTable.Get(bs.getMacAddress());
if (bsFromTable != null) {
GPSLocation locationFromTable = bsFromTable.getBaseStationLocationUsingAverage();
if (locationFromTable != null) {
averageLong += locationFromTable.getLongitude();
averageLat += locationFromTable.getLatitude();
matchedCount++;
}else{
averageLong++;
averageLong--;
}
}else{
averageLong++;
averageLong--;
}
}
if (averageLong != 0) {
averageLong /= matchedCount;
}
if (averageLat != 0) {
averageLat /= matchedCount;
}
if (averageLat != 0 && averageLong != 0) {
resultRecord.setLocationPoint(new GPSLocation(averageLong, averageLat, 0));
} else {
return null;
}
}
}
答案 0 :(得分:0)
这些峰值最有可能的原因是“停止世界”#34;由GC引起的休息。你无法阻止这种情况的发生。最好的尝试是在进行第一次测量之前调用System.gc()一次。
答案 1 :(得分:0)
您需要在这些时间跟踪程序正在执行的操作。例如,您的代码中有一些行可以调用另一个服务(可能不受您控制)。您还需要对此服务进行分析。
您可以通过自己添加大量此时控制测量值,或使用 jVisualVM 或新Relic 等配置文件工具来完成此操作。
最后一个,您可以在在线平台上分析图形并接收反馈。
分析完所有数据后,您可以开始更改程序中的某些功能,甚至可以在必要时更新JVM中的功能。例如,如果问题与完整GC 过程有关,则可以更改JVM在启动时使用的GC 算法。
答案 2 :(得分:0)
对于非常快速的操作,有很大的机会&#34;某些事情&#34;发生。它可以是GC,它可以是另一个处理时间的过程(就像你的antivir决定立即检查一些东西)。
但是有一个简单的解决方案。如果你想知道&#34; true&#34;处理时间,您只需要多次运行方法体并计算平均时间。它确保即使&#34;东西&#34;碰巧,它对你的结果影响很小。
这是一个非常简单的例子:
int count = 0;
long start = System.nanoTime();
for (int i = 0; i < 1000000; i++) {
count++;
}
long end = System.nanoTime();
long totalTime = end - start;
System.out.println("Incrementing int variable cost you + " + (totalTime/(double) 1000000) + " nanoseconds");
您可以尝试运行此功能,如您所见,如果您反复运行它,则totalTime几乎相同。
答案 3 :(得分:0)
尝试测量微秒范围内的时间跨度很难(或几乎不可能)。 System.nanoTime()
调用中使用的计时器的分辨率是有限的,取决于操作系统(可以轻松找到更多详细信息,例如System.currentTimeMillis vs System.nanoTime)
此外,可能存在任意干扰,包括绑定到JVM的那些(即垃圾收集运行),而不是用户生成的干扰(您在程序中的其他位置运行的一些其他线程) ,对于“外部”的,如你的邮件客户端弹出“你有邮件”窗口,或者是在无聊的,无聊的基准测试运行期间由后台运行的MP3播放器引起的延迟; )
分析器显然是识别复杂系统瓶颈的首选。在这种情况下,分析器可能有助于“缩放”到方法中:从此方法完成的任何方法调用都可能是“尖峰”的原因。例如,像sensorValue.getSignalValue(i)
或bs.getMacAddress()
之类的调用可以通过本机库进行一些奇怪的硬件中断访问...或者可能在后台随机启动“MineSweeper”,谁知道。
一个有趣的问题也是你真正想要衡量的。鉴于这个问题,它可能听起来很幼稚,但是:为什么尖峰很重要? spike本身真的是一个问题,还是只是一个吸引你好奇心的神器?我无法想象这种方法对100次调用的执行时间是100x1ms还是99x1ms + 1x2ms是否与实践相关。如果这是用于某种“微基准测试”,你至少应该计算超过100次调用的平均时间(并且最好使用微基准测试框架)。