10

我目前正在评估 Apache StopWatch 和 Guava 的 Stopwatch 之间的实现,前者中的拆分功能让我很感兴趣,但我很难理解它到底做了什么,以及它有什么价值。

根据秒表的文档:https ://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/time/StopWatch.html

split() 手表在后台继续运行时获取时间。unsplit() 将删除拆分的效果。此时,这三个选项再次可用。

我发现了一些例子,比如this,它提供的很少,因为它看起来 split 只是累积的。该页面说该方法用于“分割时间”,我根据该方法得出了同样多的结论,但该页面没有提及这实际上意味着什么。甚至看起来这个例子是完全错误的,因为文档建议你应该再次出现unsplit在你面前split

我最初认为它适用于以下用例:

StopWatch stopwatch = StopWatch.createStarted();
do something for 5 seconds
stopwatch.split();
do something for 10 seconds
stopwatch.stop();
System.out.println(stopwatch.getTime());
System.out.println(stopwatch.getSplitTime());

我认为秒表总时间读作 15 秒,秒表分割时间读作 10 或 5 秒,但似乎这两种方法都输出 15 秒。

接下来,我认为拆分值可能是您可以采用的增量,然后从总计时器中删除,例如:

StopWatch stopwatch = StopWatch.createStarted();
do something for 5 seconds
stopwatch.split();
do something for 10 seconds
stopwatch.unsplit();
stopwatch.stop();
System.out.println(stopwatch.getTime());
// System.out.println(stopwatch.getSplitTime()); errors because of unsplit

我的想法是拆分时间为 10 秒,当从主计时器未拆分时,主计时器将读取为 5 秒......但这似乎与suspend()通话没有什么不同......我也试过这个,并且尽管如此,时间对我来说还是一样的。

我在这里遗漏了什么,还是我对这应该做的事情的解释都是错误的?

4

1 回答 1

16

这是(它在内部调用这个其他函数)的源代码getSplitTime()

public long getSplitNanoTime() {
  if (this.splitState != SplitState.SPLIT) {
     throw new IllegalStateException("Stopwatch must be split to get the split time. ");
  }
   return this.stopTime - this.startTime;
}

所以它会返回stopTime-startTime。当心stopTime是骗子让你困惑。

这是代码stop()

public void stop() {
  if (this.runningState != State.RUNNING && this.runningState != State.SUSPENDED) {
    throw new IllegalStateException("Stopwatch is not running. ");
  }
  if (this.runningState == State.RUNNING) 
  {
    //is this the same stopTime getSplitTime uses? yep, it is
     this.stopTime = System.nanoTime(); 
  }
  this.runningState = State.STOPPED;
}

那会发生什么?

调用会stop()更新stopTime变量并使秒表“忘记”上次拆分的时间。

两者split()stop()修改相同的变量 ,当您在进程结束stopTime时调用时,该变量会被覆盖。stop()

尽管共享同一个变量可能看起来很奇怪,但它确实很有意义,因为 ansplittedTime永远StopWatch不应该大于总经过时间。所以这是一个关于在StopWatch.

这是 的代码split(),以便看到这两种方法都使用stopTime

public void split() {
   if (this.runningState != State.RUNNING) {
      throw new IllegalStateException("Stopwatch is not running. ");
    }
    this.stopTime = System.nanoTime(); // you again little f..
    this.splitState = SplitState.SPLIT;
}

这就是为什么这个可爱的 Apache 骗子会在 splittedTime 上显示 15 秒:因为stop()更新后的stopTime变量getSplitTime()将用于返回其值。(第一个代码片段

请注意函数的简单性split()这也几乎不能回答 OP 的问题)。它负责:

  1. 检查是否StopWatch正在运行。
  2. 标记一个新的stopTime.
  3. 设置splitStateSPLIT.

                                      TLDR lol

getSplitTime()在停止之前调用StopWatch 应该向您显示所需的值

  1. stopTime暂时不会更新stop()
  2. 返回值现在将匹配 lastsplit()startTime.

一些例子:(是的,周六晚上编辑,因为我需要社交生活

StopWatch stopwatch = StopWatch.createStarted();
do something for 5 seconds
stopwatch.split(); //stopTime is updated [by split()]
System.out.println(stopwatch.getSplitTime()); // will show 5 seconds
do something for 10 seconds
System.out.println(stopwatch.getSplitTime()); // will also show 5 seconds
stopwatch.stop(); //stopTime is updated again [by stop()]
System.out.println(stopwatch.getTime()); // 15s
System.out.println(stopwatch.getSplitTime()); // 15s

另一个:

StopWatch stopwatch = StopWatch.createStarted();
do something for 5 seconds
stopwatch.split(); 
System.out.println(stopwatch.getSplitTime()); // 5s
do something for 10 seconds
stopwatch.split(); 
System.out.println(stopwatch.getSplitTime()); // 15s
do something for 1 second
stopwatch.stop();
System.out.println(stopwatch.getTime()); // 16s

最后一个。嘲笑时间sleeps,只是为了好玩,你知道的。我太无聊了,我真的导入了 apache jar 以便在本地进行测试

StopWatch stopwatch = StopWatch.createStarted();
Thread.sleep(5000);
stopwatch.split(); 
System.out.println(stopwatch.getSplitTime()); // 5s
Thread.sleep(10000);
stopwatch.split(); 
System.out.println(stopwatch.getSplitTime()); // 15s

stopwatch.reset();  // allows the stopWatch to be started again
stopwatch.start();  // updates startTime

Thread.sleep(2000);
stopwatch.split(); 
System.out.println(stopwatch.getSplitTime()); // 2s
Thread.sleep(1000);
stopwatch.stop();
System.out.println(stopwatch.getTime());      // 3s
System.out.println(stopwatch.getSplitTime()); // 3s
//it was so fun putting the sleeps

请注意,调用getSplitTime()stopWatch不会引发任何异常,因为该方法只会检查splitStateis 是否SPLIT

混淆可能是由以下两个事实引起的:

  1. 该代码允许您stop()不管SplitState,使您的最后一个split()徒劳无功而你不知道。徒劳的,我喜欢这个词。不得不以某种方式将其包含在我的答案中。徒劳的
  2. 它还允许您检查splittedTime停止的手表(如果它仍然处于开启SPLIT状态),它实际上只会返回上次start()和停止时间之间的总经过时间。(小骗子)

在这种情况下,秒表同时停止和拆分getTime()并且getSplitTime()在调用 after 时始终显示相同的值stop()


[个人和主观意见]

假设您有一个Counters具有不同变量的类来检查经过的时间。您还希望每 60 秒输出每个操作的总经过时间。在此示例中,counters是一个拥有两个变量的Counters类的实例:和,它将在特定时间间隔 ( 60 秒) 内累积每个操作中经过的时间。这只是一个假设每次迭代时间少于 1000 毫秒的示例(因此它总是显示经过时间为 60 秒):longfileTimesendTime

long statsTimer = System.currentTimeMillis();
while (mustWork)
{
    long elapsedStatsTimer = System.currentTimeMillis()-statsTimer; //hits 60185 
   
    if (elapsedStatsTimer  > 60000)
    {
       //counters.showTimes()
       System.out.println("Showing elapsed times for the last "+
                            (elapsedStatsTimer/1000)+ " secs"); //(60185/1000) - 60 secs
       System.out.println("Files time: "+counters.fileTime+" ms"); //23695 ms
       System.out.println("Send time : "+counters.sendTime+" ms"); //36280 ms          
       long workTime = counters.sendTime+counters.fileTime;
       System.out.println("Work time : "+workTime+" ms"); //59975 ms
       System.out.println("Others    : "+(elapsedStatsTimer-workTime)+" ms"); //210 ms
       //counters.reset()
       counters.fileTime=0;
       counters.sendTime=0;
       statsTimer= System.currentTimeMillis();
     }
     
     long timer = System.currentTimeMillis();
     //do something with a file
     counters.fileTime+=System.currentTimeMillis-timer;
     timer = System.currentTimeMillis();
     //send a message
     counters.sendTime+=System.currentTimeMillis()-timer;
}

Counters该类可以实现reset()and函数,showTimes()以清理上面的代码。它还可以管理elapsedStatsTimer变量。这只是简化其行为的示例。

对于这个需要持续测量不同操作的用例,我认为这种方式更易于使用,并且似乎具有相似的性能,因为StopWatch内部制作完全相同。但是,嘿,这只是我的方式:)。

我将以一种光荣和徒劳的方式接受对这一观点的反对票。

我很想以一分钟的沉默结束,以纪念unsplit(),这可能是有史以来最不相关的方法之一。

[/个人主观意见]


刚刚注意到TLDR部分实际上比上一部分大:_)

于 2020-07-08T23:14:41.300 回答