В чем смысл Apache Lang3 StopWatch.split ()? - PullRequest
5 голосов
/ 09 июля 2020
• 1000 к документации для секундомера: https://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/time/StopWatch.html

split (), чтобы получить время, пока часы продолжаются в фоновом режиме. unsplit () удалит эффект разделения. На данный момент эти три варианта снова доступны.

И я нашел несколько примеров, таких как this , которые предлагают очень мало, поскольку кажется, что разделение - это всего лишь совокупность. На странице говорится, что этот метод предназначен для «разделения времени», что, как я понял, основано на методе, но на странице не упоминается, что это на самом деле означает. Может показаться даже, что этот пример совершенно неверен, потому что в документации предлагается 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() ... Я тоже пробовал это, и тайминги, тем не менее, остались для меня такими же.

Я что-то упускаю здесь, или моя интерпретация того, что это должно делать, неверна?

1 Ответ

8 голосов
/ 09 июля 2020

Это исходный код для 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() в конце вашего процесса.

Хотя совместное использование одной и той же переменной может выглядеть странно, это действительно имеет смысл, поскольку splittedTime из 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 лжец показывает вам 15 секунд в splittedTime: поскольку stop() обновил, stopTime переменная getSplitTime() будет использовать для возврата своего значения. ( первый фрагмент кода )

Обратите внимание на простоту функции split() ( это также почти не отвечает на вопрос OP ). Он отвечает за:

(Проверка, работает ли StopWatch.) Маркировка нового stopTime. Установка splitState на SPLIT.

И все. Вау, так тяжело, точно часы устали .

                                      TLDR lol

Вызов getSplitTime() перед остановкой StopWatch должен показать вам желаемое значение :

  1. stopTime не будет быть обновленным stop() еще.
  2. Возвращаемое значение теперь будет соответствовать времени, прошедшему между последним split() и 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() на остановленном Watch не вызовет никаких исключений, потому что метод будет проверять только, является ли splitState SPLIT.

Путаница может быть вызвана этими двумя фактами:

  1. Код позволяет stop() независимо от SplitState, делая ваш последний split() бесполезным без вашего ведома. Бесполезно, я люблю это слово. Пришлось как-то включить это в свой ответ. Futileeee
  2. Это также позволяет вам проверить splittedTime на остановленных часах (если они все еще находятся в состоянии SPLIT), когда он действительно просто вернет общее время, прошедшее между последнее start() и время остановки. (маленький лжец)

В этом сценарии , где секундомер остановлен и разделен одновременно, , getTime() и getSplitTime() всегда будут показывать то же значение при вызове после stop().

[Личное и субъективное мнение]

Допустим, у вас есть класс Counters с разными переменными для проверки прошедшего времени. Вы также хотите выводить общее прошедшее время для каждой операции каждые 60 секунд. В этом примере counters является экземпляром класса Counters, который владеет двумя long переменными: fileTime и sendTime, которые будут накапливать время, прошедшее с каждой операции в течение указанного c интервал ( 60 с ). Это просто пример, в котором предполагается, что каждая итерация занимает менее 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;
}

Этот класс Counters может реализовать функции reset() и showTimes(), чтобы очистить приведенный выше код. Он также может управлять переменной elapsedStatsTimer. Это просто пример для упрощения его поведения.

Для этого варианта использования, в котором вам нужно постоянно измерять различные операции , я думаю, что этот способ проще для использовать и, похоже, имеет аналогичную производительность, поскольку StopWatch внутренне делает то же самое. Но послушайте, это просто мой способ сделать это :) 1211 * с минутой молчания в честь unsplit(), что может быть одним из самых неуместных методов, которые я когда-либо видел.

[Личное и субъективное мнение]

...