简体   繁体   English

Apache Lang3 StopWatch.split() 的意义何在?

[英]What is the point of Apache Lang3 StopWatch.split()?

I am currently evaluating implementations between Apache StopWatch and Guava's Stopwatch and the split functionality in the former intrigued me, but I am struggling to understand what exactly it does, and what value it has.我目前正在评估 Apache 秒表和番石榴的秒表之间的实现,前者的拆分功能让我很感兴趣,但我很难理解它到底做了什么,以及它有什么价值。

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

split() the watch to get the time whilst the watch continues in the background. split() 手表在后台继续运行时获取时间。 unsplit() will remove the effect of the split. unsplit() 将删除拆分的效果。 At this point, these three options are available again.此时,这三个选项再次可用。

And I found some examples, such as this , which offer very little, since it appears split is just cumulative.我发现了一些例子,比如this ,它提供的很少,因为它看起来 split 只是累积的。 The page says the method is for "splitting the time", which I figured as much based on the method, but the page makes no mention to what that actually means.该页面说该方法用于“分割时间”,我根据该方法得出了同样多的结论,但该页面没有提及这实际上意味着什么。 It would even appear that this example is utterly wrong, because the docs suggest that you should unsplit before you split again.甚至看起来这个例子是完全错误的,因为文档建议你应该在再次unsplit之前取消split

I initially thought it was for the following usecase:我最初认为它适用于以下用例:

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());

I thought that stopwatch total time would read as 15 seconds, and stopwatch split time would read as either 10 or 5 seconds, but it appears that both methods output 15 seconds.我认为秒表总时间读作 15 秒,秒表分割时间读作 10 或 5 秒,但似乎这两种方法 output 都是 15 秒。

Next, I thought maybe the split value is a delta you can take, and then remove from the total timer, something like:接下来,我认为拆分值可能是您可以采用的增量,然后从总计时器中删除,例如:

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

My thought here was that the split time would be 10 seconds, and when unsplit from the main timer, the main timer would read as 5 seconds... but this seems no different from a suspend() call... I also tried this, and the timings remain the same nonetheless for me.我的想法是拆分时间为 10 秒,当从主计时器未拆分时,主计时器将读取为 5 秒......但这似乎与suspend()调用没有什么不同......我也试过这个,而且时间对我来说还是一样的。

Am I missing something here, or is my interpretation of what this is supposed to do all wrong?我在这里遗漏了什么,还是我对这应该做的事情的解释都是错误的?

This is the source code for getSplitTime() ( it calls this other function internally ):这是getSplitTime()源代码它在内部调用另一个 function ):

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;
}

So it will return stopTime-startTime .所以它会返回stopTime-startTime Beware of stopTime .当心stopTime It's the liar that's confusing you.是骗子让你困惑。

This is the code for stop() :这是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;
}

What's happenning then?那会发生什么?

Calling stop() updates the stopTime variable and makes the stopwatch "forget" the last time it was splitted.调用stop()会更新stopTime变量并使秒表“忘记”上次拆分的时间。

Both split() and stop() modify the same variable, stopTime , which is overrided when you call stop() at the end of your process. split()stop()都修改了相同的变量stopTime ,当您在进程结束时调用stop()时,该变量会被覆盖。

Although sharing the same variable may look wierd, it really makes sense, as an splittedTime of an StopWatch should never be bigger than the total elapsed time.尽管共享同一个变量可能看起来很奇怪,但它确实很有意义,因为StopWatchsplittedTime永远不应大于总经过时间。 So it's a game regarding the order of the functions executed in the StopWatch .所以这是一个关于StopWatch中执行的功能顺序的游戏。

This is the code for split() , in order to see that both methods do use stopTime :这是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;
}

That's why this little adorable Apache liar shows you 15 seconds on the splittedTime: because stop() updated the stopTime variable getSplitTime() will use to return its value.这就是为什么这个可爱的 Apache 骗子会在 splittedTime 上显示 15 秒:因为stop()更新了stopTime变量getSplitTime()将用于返回其值。 ( the first code snippet ) 第一个代码片段

Note the simplicity of the split() function ( this also barely answers OP's question ).请注意split() function 的简单性(这也几乎没有回答 OP 的问题)。 It is responsible of:它负责:

  1. Checking wether the StopWatch is running.检查StopWatch是否正在运行。
  2. Marking a new stopTime .标记一个新的stopTime
  3. Setting the splitState to SPLIT .splitState设置为SPLIT

                                      TLDR lol

Calling getSplitTime() before stopping the StopWatch should show you the desired value :在停止StopWatch之前调用getSplitTime()应该会显示所需的值

  1. stopTime won't be updated by stop() yet. stopTime不会被stop()更新。
  2. The returning value will now match the time elapsed between the last split() and the startTime .返回值现在将匹配上次split()startTime之间经过的时间。

Some examples: ( yes, editing at saturday night cause I need a social life )一些例子:(是的,周六晚上编辑,因为我需要社交生活

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

Another one:另一个:

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

And a last one.最后一个。 Mocked the time with sleeps , just for the fun, you know.sleeps来嘲笑时间,只是为了好玩,你知道的。 I was so bored I really imported the apache jar in order to test this locally :我太无聊了,我真的进口了 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

Note that calling getSplitTime() on an stopped Watch won't throw any exception, because the method will only check wheter the splitState is SPLIT .请注意,在停止的Watch上调用getSplitTime()不会引发任何异常,因为该方法只会检查splitState是否为SPLIT

The confusion may be caused by these two facts:混淆可能是由以下两个事实引起的:

  1. The code allows you to stop() regardless of the SplitState , making your last split() futile without you being aware.该代码允许您stop()而不管SplitState ,使您的最后一个split()在您不知道的情况下徒劳无功。 Futile, I love that word.徒劳的,我喜欢这个词。 Had to include it in my answer somehow.不得不以某种方式将其包含在我的答案中。 Futileeee徒劳的
  2. It also allows you to check the splittedTime on an stopped watch (if it is still on SPLIT state), when it really just will return the total elapsed time between the last start() and the stopping time.它还允许您在停止的手表上检查splittedTime (如果它仍处于SPLIT状态),它实际上只会返回上次start()和停止时间之间的总经过时间。 (little liar) (小骗子)

In this scenario, where the stopwatch is stopped and splitted at the same time , getTime() and getSplitTime() will always show the same value when called after stop() .在这种情况下,秒表同时停止和拆分, getTime()getSplitTime()stop()之后调用时将始终显示相同的值。


[Personal and subjective opinion] [个人和主观意见]

Let's say you have a Counters class with different variables to check elapsed times.假设您有一个带有不同变量的Counters class 来检查经过的时间。 You also want to output the total elapsed time for each operation, every 60 seconds.您还希望 output 每次操作的总经过时间,每 60 秒。 In this example, counters is an instance of a Counters class that owns two long variables: fileTime and sendTime , that will accumulate the elapsed time within each operation during an specific interval ( 60s ).在此示例中, countersCounters class 的一个实例,它拥有两个long变量: fileTimesendTime ,它们将在特定时间间隔 ( 60s ) 内累积每个操作中的经过时间。 This is just an example that assumes each iteration takes less than 1000 ms (so it will always show 60 seconds on the elapsed time):这只是一个假设每次迭代时间少于 1000 毫秒的示例(因此它总是显示经过时间为 60 秒):

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;
}

That Counters class could implement the reset() and showTimes() functions, in order to clean up the code above. Counters class 可以实现reset()showTimes()函数,以清理上面的代码。 It could also manage the elapsedStatsTimer variable.它还可以管理elapsedStatsTimer变量。 This is just an example to simplify its behaviour.这只是简化其行为的示例。

For this use case, in which you need to measure different operations persistently , I think this way is easier to use and seems to have a similar performance, as the StopWatch internally makes the exact same thing.对于这种需要持续测量不同操作的用例,我认为这种方式更易于使用并且似乎具有相似的性能,因为StopWatch在内部进行完全相同的事情。 But hey, it's just my way to do it: ).但是,嘿,这只是我的做法:)。

I will accept downvotes for this opinion in an honorable and futile way.我将以一种光荣和徒劳的方式接受对这一观点的反对票。

I would love to finish with a minute of silence in honour of unsplit() , which may be one of the most irrelevant methods ever existed.我很想以一分钟的沉默来结束unsplit() ,这可能是有史以来最不相关的方法之一。

[/Personal and subjective opinion] [/个人主观意见]


Just noticed TLDR section is actually bigger than the previous section:_ )刚刚注意到TLDR部分实际上比上一部分大:_)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM