Як встановити час для швидкості виконання програми Java


85

Як ви вимірюєте час виконання програми Java? Я не впевнений, який клас мені слід використовувати для цього.

Я начебто шукаю щось на зразок:

// Some timer starts here
for (int i = 0; i < length; i++) {
  // Do something
}
// End timer here

System.out.println("Total execution time: " + totalExecutionTime);

Відповіді:


139
final long startTime = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
  // Do something
}
final long endTime = System.currentTimeMillis();

System.out.println("Total execution time: " + (endTime - startTime));

2
насправді це має бути nanoTime
Євген

6
Не повинно бути nanoTime. Дивіться відповідь rhu.
fabspro

4
Чи є якась особлива причина, через яку ви тут використали "остаточний"? Що було б інакше, якби ви випустили це ключове слово?
dijxtra

9
Використання @dijxtra finalмає ту перевагу, що ви не можете випадково призначити його (а також інші переваги, такі як доступ до анонімного класу тощо). У цьому коді це не має значення. Це досить розповсюджена практика робити все finalі finalрозблоковувати це лише за потреби.
wchargin

1
Тестований код, разом із вимірюванням часу, слід запускати кілька разів, а перший результат слід відкидати. Перший, швидше за все, включатиме час завантаження класу і т. Д. Запустивши його кілька разів, звичайно, ви отримаєте середнє значення, яке є більш корисним і надійним.
Арун Рамакрішнан

34

Майте на увазі, що є деякі проблеми, які System#nanoTime()не можуть бути надійно використані на багатоядерних процесорах для запису минулого часу ... кожне ядро ​​має власний TSC ( лічильник позначок часу ): цей лічильник використовується для отримання нано часу (насправді це кількість галочок після завантаження процесора).

Отже, якщо ОС не виконує деякої деформації часу TSC, щоб синхронізувати ядра, тоді, якщо потік стає запланованим на одному ядрі при початковому зчитуванні часу, а потім перемикається на інше ядро, відносний час може епізодично здаватися стрибком назад і вперед.

Я спостерігав це деякий час тому на AMD / Solaris, коли час, що минув між двома точками хронометражу, іноді повертався як негативні значення, так і несподівано великі позитивні числа. Були виправлення ядра Solaris та налаштування BIOS, необхідні для примусового використання AMD PowerNow! вимкнено, що вирішило це.

Крім того, існує (AFAIK) поки що невиправлена ​​помилка при використанні Java System#nanoTime()у середовищі VirtualBox; спричиняючи всілякі химерні проблеми з переривчастими потоками для нас, оскільки велика частина java.util.concurrencyпакету покладається на нано час.

Дивіться також:

Чи System.nanoTime () абсолютно марний? http://vbox.innotek.de/pipermail/vbox-trac/2010-January/135631.html


9

Ви отримуєте поточний системний час у мілісекундах:

final long startTime = System.currentTimeMillis();

Тоді ви робите те, що збираєтеся робити:

for (int i = 0; i < length; i++) {
  // Do something
}

Тоді ви бачите, скільки часу це зайняло:

final long elapsedTimeMillis = System.currentTimeMillis() - startTime;

Відповідь BalusC також є правильною; це залежить від необхідної роздільної здатності таймера та від того, чому вам потрібні хронометраж.
Джонатан Файнберг,

9

Ви можете скористатися System#nanoTime(). Отримайте його до і після виконання і просто підрахуйте. Це переважно вище, System#currentTimeMillis()оскільки воно має кращу точність. Залежно від використовуваного обладнання та платформи, в іншому випадку ви можете отримати неправильний проміжок часу, що минув. Тут з Core2Duo в Windows, приблизно від 0 до ~ 15 мс насправді нічого не можна розрахувати.

Більш досконалий інструмент - це профайлер .


Таймер у Windows не має особливо гарної роздільної здатності за замовчуванням. Там є таймер високої продуктивності теж, але це набагато складніше, навіть з C і Java не (AFAIK) забезпечує доступ до цього мінімуму рівня вози , запряжені воли без JNI стуку.
Donal Fellows

1
nanoTime()має одну проблему (принаймні у Windows); позначка часу характерна для ядра процесора. У мене була програма, яка отримала негативний час виконання, оскільки вона отримала позначку часу "старт" на одному ядрі та мітку часу "зупинка" на іншому ядрі.
gustafc

3

Для простих речей може працювати System.currentTimeMillis () .

Це насправді настільки часто, що моя IDE налаштована так, що після введення "t0" вона генерує мені такий рядок:

final long t0 = System.currentTimeMillis()

Але для більш складних речей ви, мабуть, захочете використовувати статистичні вимірювання часу, як тут (прокрутіть трохи вниз і подивіться на виражені часові виміри, включаючи стандартні відхилення тощо):

http://perf4j.codehaus.org/devguide.html


+1 за вказівку коду автогенератора. Я весь час використовую подібне твердження і не знав про вставку шаблонів коду. Щойно дізнався, як це зробити із затемненням, і це точно допоможе!
Джейсон,

Усі послуги Codehaus припинені. Ваше посилання зараз недійсне.
naXa

2

Використовуючи AOP / AspectJ та @Loggableанотації з jcabi-аспектів, ви можете зробити це просто та компактно:

@Loggable(Loggable.DEBUG)
public String getSomeResult() {
  // return some value
}

Кожен виклик цього методу надсилатиметься до реєстраційного об'єкта SLF4J з DEBUGрівнем реєстрації. І кожне повідомлення журналу включатиме час виконання.


2

Ось декілька способів знайти час виконання в Java:

1) System.nanoTime ()

long startTime = System.nanoTime();
.....your code....
long endTime   = System.nanoTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in nanoseconds  : " + totalTime);
System.out.println("Execution time in milliseconds : " + totalTime / 1000000);

2) System.currentTimeMillis ()

long startTime = System.currentTimeMillis();
.....your code....
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds  : " + totalTime);

3) Миттєво. Тепер ()

long startTime = Instant.now().toEpochMilli();
.....your code....
long endTime = Instant.now().toEpochMilli();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);

або

Instant start = Instant.now();
.....your code....
Instant end = Instant.now();
Duration interval = Duration.between(start, end);
System.out.println("Execution time in seconds: " +interval.getSeconds());

4) Date.getTime ()

long startTime = new Date().getTime();
.....your code....
long endTime = new Date().getTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);

1

використовувати довго startTime=System.currentTimeMillis()для часу запуску, у верхній частині циклу

покласти long endTime= System.currentTimeMillis();поза кінець петлі. Вам доведеться відняти значення, щоб отримати час роботи в мілісекундах.

Якщо вам потрібен час у наносекундах, перевірте System.nanoTime()


1

Я створив функцію вищого порядку, яка приймає код, який ви хочете виміряти / як лямбда:

class Utils {

    public static <T> T timeIt(String msg, Supplier<T> s) {
        long startTime = System.nanoTime();
        T t = s.get();
        long endTime = System.nanoTime();
        System.out.println(msg + ": " + (endTime - startTime) + " ns");
        return t;
    }

    public static void timeIt(String msg, Runnable r) {
       timeIt(msg, () -> {r.run(); return null; });
    }
}

Називайте це так:

Utils.timeIt("code 0", () ->
        System.out.println("Hallo")
);

// in case you need the result of the lambda
int i = Utils.timeIt("code 1", () ->
        5 * 5
);

Вихід:

код 0: 180528 нс
код 1: 12003 нс

Особлива подяка Енді Тернеру, який допоміг мені скоротити надмірність. Дивіться тут .



0

Ви також можете спробувати Perf4J. Це акуратний спосіб робити те, що ви шукаєте, і допомагає у зведених статистичних даних про ефективність, таких як середнє, мінімальне, максимальне, стандартне відхилення та транзакції в секунду протягом заданого періоду часу. Витяг з http://perf4j.codehaus.org/devguide.html :

StopWatch stopWatch = new LoggingStopWatch();

try {
    // the code block being timed - this is just a dummy example
    long sleepTime = (long)(Math.random() * 1000L);
    Thread.sleep(sleepTime);
    if (sleepTime > 500L) {
        throw new Exception("Throwing exception");
    }

    stopWatch.stop("codeBlock2.success", "Sleep time was < 500 ms");
} catch (Exception e) {
    stopWatch.stop("codeBlock2.failure", "Exception was: " + e);
}

Вихід:

INFO: start[1230493236109] time[447] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493236719] time[567] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493237286] time[986] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493238273] time[194] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238467] time[463] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238930] time[310] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239241] time[610] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493239852] time[84] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239937] time[30] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239968] time[852] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]

0
public class someClass
{
   public static void main(String[] args) // your app start point
   {
       long start = java.util.Calendar.getInstance().getTimeInMillis();

       ... your stuff ...

       long end = java.util.Calendar.getInstance().getTimeInMillis();
       System.out.println("it took this long to complete this stuff: " + (end - start) + "ms");
   }
}

0

Правильним способом цього є використання System.currentTimeMillis (). Але якщо ви використовуєте командний рядок і хочете приблизно і швидко встановити час для всієї програми, подумайте про:

time java App

що дозволяє вам не змінювати код і час роботи вашого додатка.


Це залежить від того, як ви запускаєте код. Якщо це шматок коду, на якому запущений сервер, тоді ви вкажете неправильний час запуску.
Арун Рамакрішнан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.