Как измерить время выполнения функции

Мне нужно получить время выполнения в миллисекундах.

Первоначально я задал этот вопрос еще в 2008 году. Тогда был принят новый ответ: использовать функцию Date(). GetTime(). Однако теперь мы все можем согласиться с тем, что использование стандартного API performance.now () более целесообразно. Поэтому я меняю принятый ответ на этот.

33 ответа

Решение

Использование performance.now ():

var t0 = performance.now();

doSomething();   // <---- The function you're measuring time for 

var t1 = performance.now();
console.log("Call to doSomething took " + (t1 - t0) + " milliseconds.")

NodeJs: необходимо импортировать performance учебный класс


Использование console.time: (нестандартные) (уровень жизни)

console.time('someFunction');

someFunction(); // Whatever is timed goes between the two "console.time"

console.timeEnd('someFunction');

Примечание:
Строка, передаваемая в time() а также timeEnd() методы должны совпадать
(чтобы таймер закончился как положено).

console.time() Документации:

  1. Документация NodeJS относительно
  2. MDN (клиентская) документация

Использовать новый Date().getTime()

Метод getTime () возвращает количество миллисекунд с полуночи 1 января 1970 года.

ех.

var start = new Date().getTime();

for (i = 0; i < 50000; ++i) {
// do something
}

var end = new Date().getTime();
var time = end - start;
alert('Execution time: ' + time);

Не используйте Date(). Читай ниже.

использование performance.now():

<script>
var a = performance.now();
alert('do something...');
var b = performance.now();
alert('It took ' + (b - a) + ' ms.');
</script>

Работает на:

  • IE 10 ++

  • FireFox 15 ++

  • Chrome 24 ++

  • Safari 8 ++

  • Опера 15 ++

  • Android 4.4 ++

  • и т. д.

console.time может быть жизнеспособным для вас, но это нестандартно §:

Эта функция является нестандартной и не соответствует стандартам. Не используйте его на производственных сайтах, выходящих в Интернет: он не будет работать для каждого пользователя. Также могут быть большие несовместимости между реализациями, и поведение может измениться в будущем.

Помимо поддержки браузера, performance.now Похоже, что у него есть потенциал, чтобы обеспечить более точные сроки, так как это, похоже, голая версия console.time,


Кроме того, НИКОГДА не используйте Date за что угодно, потому что на него влияют изменения в "системном времени". Это означает, что мы получим недопустимые результаты, такие как "отрицательное время", когда у пользователя нет точного системного времени:

В октябре 2014 года мои системные часы перестали работать, и угадайте, что... Я открыл Gmail и увидел все электронные письма моего дня, "отправленные 0 минут назад ". И я думал, что Gmail должен быть создан инженерами мирового уровня из Google.......

(Установите системные часы на год назад и перейдите в Gmail, чтобы мы все могли посмеяться. Возможно, когда-нибудь у нас будет Зал позора для JS Date.)

Google Spreadsheet's now() Функция также страдает от этой проблемы.

Единственный раз, когда вы будете использовать Date когда вы хотите показать пользователю его системное время. Не тогда, когда вы хотите получить время или что-то измерить.

Если вам нужно получить время выполнения функции на локальном компьютере разработчика, вы можете использовать инструменты профилирования вашего браузера или консольные команды, такие как console.time() а также console.timeEnd(),

Все современные браузеры имеют встроенные профилировщики JavaScript. Эти профилировщики должны давать наиболее точные измерения, поскольку вам не нужно изменять существующий код, что может повлиять на время выполнения функции.

Для профилирования вашего JavaScript:

  • В Chrome нажмите F12 и выберите вкладку " Профили ", затем выберите " Сборка профиля ЦП JavaScript".
  • В Firefox установите / откройте Firebug и нажмите кнопку " Профиль".
  • В IE 9+ нажмите F12, нажмите Script или Profiler (в зависимости от вашей версии IE).

Кроме того, на своем компьютере разработки вы можете добавить инструментарий в свой код с помощью console.time() а также console.timeEnd(), Эти функции, поддерживаемые в Firefox11+, Chrome2+ и IE11+, сообщают о таймерах, через которые вы запускаете / останавливаете console.time(), time() принимает заданное пользователем имя таймера в качестве аргумента и timeEnd() затем сообщает о времени выполнения с момента запуска таймера:

function a() {
  console.time("mytimer");
  ... do stuff ...
  var dur = console.timeEnd("myTimer"); // NOTE: dur only works in FF
}

Обратите внимание, что только Firefox возвращает прошедшее время в timeEnd() вызов. Другие браузеры просто сообщают результат на консоль разработчика: возвращаемое значение timeEnd() не определено

Если вы хотите узнать время выполнения функции, вам придется использовать свой код. У вас есть пара вариантов. Вы можете просто сохранить время начала и окончания, запросив new Date().getTime():

function a() {
  var start = new Date().getTime();
  ... do stuff ...
  var end = new Date().getTime();
  var dur = end - start;
}

Тем не менее Date объект имеет разрешение только в миллисекундах и будет зависеть от изменений системных часов любой ОС. В современных браузерах есть лучший вариант.

Лучший вариант - использовать High Resolution Time, также известный как window.performance.now(), now() лучше, чем традиционный Date.getTime() двумя важными способами:

  1. now() является двойным с субмиллисекундным разрешением, которое представляет количество миллисекунд с начала навигации по странице. Возвращает количество микросекунд в дробной части (например, значение 1000.123 равно 1 секунде и 123 микросекундам).

  2. now() монотонно увеличивается. Это важно как Date.getTime() возможно, может перейти вперед или даже назад при последующих вызовах. Примечательно, что если системное время ОС обновляется (например, синхронизация атомных часов), Date.getTime() также обновляется. now() гарантированно всегда будет монотонно увеличиваться, поэтому на него не влияет системное время ОС - оно всегда будет временем настенных часов (при условии, что ваши настенные часы не атомарные...).

now() можно использовать практически в любом месте, new Date().getTime(), + new Date и т Date.now() являются. Исключением является то, что Date а также now() времена не смешиваются, как Date основан на эпохе Unix (количество миллисекунд с 1970 года), в то время как now() количество миллисекунд с момента начала навигации по вашей странице (поэтому оно будет намного меньше, чем Date).

Вот пример того, как использовать now():

function a() {
  var start = window.performance.now();
   ... do stuff ...
  var end = window.performance.now();
  var dur = end - start;
}

now() поддерживается в стабильных версиях Chrome, Firefox 15+ и IE10. Также доступно несколько полифилов.

Еще одна опция для измерения времени выполнения в дикой природе - UserTiming. UserTiming ведет себя аналогично console.time() а также console.timeEnd(), но он использует ту же метку времени высокого разрешения, что и now() использует (таким образом, вы получаете монотонно увеличивающиеся часы на миллисекунды) и сохраняет временные метки и длительности в PerformanceTimeline.

UserTiming имеет понятия меток (временных меток) и мер (длительностей). Вы можете определить столько, сколько хотите, и они отображаются на PerformanceTimeline.

Чтобы сохранить метку времени, вы звоните mark(startMarkName), Чтобы узнать длительность с момента вашей первой отметки, просто позвоните measure(measurename, startMarkname), Затем продолжительность сохраняется в PerformanceTimeline вместе с вашими отметками.

function a() {
  window.performance.mark("start");
  ... do stuff ...
  window.performance.measure("myfunctionduration", "start");
}

// duration is window.performance.getEntriesByName("myfunctionduration", "measure")[0];

UserTiming доступен в IE10+ и Chrome25+. Есть также доступный polyfill (который я написал).

Чтобы получить точные значения, вы должны использовать интерфейс производительности. Он поддерживается в современных версиях Firefox, Chrome, Opera и IE. Вот пример того, как его можно использовать:

var performance = window.performance;
var t0 = performance.now();
doWork();
var t1 = performance.now();
console.log("Call to doWork took " + (t1 - t0) + " milliseconds.")

Date.getTime() или же console.time() не подходят для измерения точного времени выполнения. Вы можете использовать их, если вам подходит быстрая грубая оценка. Под грубой оценкой я подразумеваю, что вы можете получить 15-60 мс сдвиг от реального времени.

Посмотрите этот блестящий пост по измерению времени выполнения в JavaScript. Автор также дает пару ссылок о точности времени JavaScript, которое стоит прочитать.

Вы также можете использовать оператор добавления здесь

 var start = +new Date();
 callYourFunctionHere();
 var end = +new Date();
 var time = end - start;
 console.log('total execution time = '+ time + 'ms');

Используйте Firebug, включите консоль и Javascript. Нажмите Профиль. Обновить. Нажмите Профиль еще раз. Посмотреть отчет.

Вот декоратор для функций синхронизации

let timed = (f) => (...args)=>{
    let start = performance.now();
    let ret = f(...args);
    console.log(`function ${f.name} took ${(performance.now()-start).toFixed(3)}ms`)
    return ret;   
}

Использование:

let test = ()=>{/*does something*/}
test = timed(test)   // turns the function into a timed function in one line
test()               // run your code as normal, logs 'function test took 1001.900ms' 

Если вы используете асинхронные функции, вы можете сделать timed асинхронно и добавить await до f(...args), и это должно работать для тех. Это становится более сложным, если вы хотите, чтобы один декоратор обрабатывал функции синхронизации и асинхронности.

process.hrtime() доступен в Node.js - он возвращает значение в наносекундах

var hrTime = process.hrtime()
console.log(hrTime[0] * 1000000 + hrTime[1] / 1000)

Можно использовать только одну переменную:

var timer = -performance.now();

// Do something

timer += performance.now();
console.log("Time: " + (timer/1000).toFixed(5) + " sec.")

timer/1000 - конвертировать миллисекунды в секунды

.toFixed(5) - обрезать лишние цифры

var StopWatch = function (performance) {
    this.startTime = 0;
    this.stopTime = 0;
    this.running = false;
    this.performance = performance === false ? false : !!window.performance;
};

StopWatch.prototype.currentTime = function () {
    return this.performance ? window.performance.now() : new Date().getTime();
};

StopWatch.prototype.start = function () {
    this.startTime = this.currentTime();
    this.running = true;
};

StopWatch.prototype.stop = function () {
    this.stopTime = this.currentTime();
    this.running = false;
};

StopWatch.prototype.getElapsedMilliseconds = function () {
    if (this.running) {
        this.stopTime = this.currentTime();
    }

    return this.stopTime - this.startTime;
};

StopWatch.prototype.getElapsedSeconds = function () {
    return this.getElapsedMilliseconds() / 1000;
};

StopWatch.prototype.printElapsed = function (name) {
    var currentName = name || 'Elapsed:';

    console.log(currentName, '[' + this.getElapsedMilliseconds() + 'ms]', '[' + this.getElapsedSeconds() + 's]');
};

эталонный тест

var stopwatch = new StopWatch();
stopwatch.start();

for (var index = 0; index < 100; index++) {
    stopwatch.printElapsed('Instance[' + index + ']');
}

stopwatch.stop();

stopwatch.printElapsed();

Выход

Instance[0] [0ms] [0s]
Instance[1] [2.999999967869371ms] [0.002999999967869371s]
Instance[2] [2.999999967869371ms] [0.002999999967869371s]
/* ... */
Instance[99] [10.999999998603016ms] [0.010999999998603016s]
Elapsed: [10.999999998603016ms] [0.010999999998603016s]

performance.now() является необязательным - просто передайте false в функцию конструктора StopWatch.

Есть несколько способов достижения этой цели:

  1. используя console.time

    console.time('function'); //run the function in between these two lines for that you need to measure time taken //by the function. ("ex. function();") console.timeEnd('function');

  2. это самый эффективный способ:использование performance.now()

ех. var v1 = performance.now(); //run the function here for which you have top measure the time var v2 = performance.now(); console.log("total time taken = "+(v2-v1)+"milliseconds";

  1. используйте +(добавить оператор) или getTime()

    var h2 = +new Date(); //or var h2 = new Date().getTime(); for(i=0;i<500;i++) {//do something} var h3 = +new Date(); //or var h3 = new Date().getTime(); var timeTaken = h3-h2; console.log("time ====", timeTaken);

Вот что происходит, когда вы применяете унарный оператор плюс к экземпляру Date: Получите значение рассматриваемого экземпляра Date. Преобразуйте его в число.

ПРИМЕЧАНИЕ: getTime() дает лучшую производительность, чем унарный оператор +.

Для дальнейшего расширения кода vsync, чтобы иметь возможность возвращать timeEnd в качестве значения в NodeJS, используйте этот маленький кусочек кода.

console.timeEndValue = function(label) { // Add console.timeEndValue, to add a return value
   var time = this._times[label];
   if (!time) {
     throw new Error('No such label: ' + label);
   }
   var duration = Date.now() - time;
   return duration;
};

Теперь используйте код так:

console.time('someFunction timer');

someFunction();

var executionTime = console.timeEndValue('someFunction timer');
console.log("The execution time is " + executionTime);


Это дает вам больше возможностей. Вы можете сохранить время выполнения, которое будет использоваться для других целей, таких как использование его в уравнениях или сохранение в базе данных, отправка удаленному клиенту через веб-сокеты, обслуживание на веб-странице и т. Д.

Используйте этот формат кода

      const startTime =new Date().getTime();

//do something 
const endTime = new Date().getTime();
console.log(`time taken ${(endTime - startTime)/1000} seconds`);

Это может помочь вам.

var t0 = date.now(); doSomething(); var t1 = date.now(); console.log("Call to doSomething took approximate" + (t1 - t0)/1000 + " seconds.")

Если вы хотите измерить время между несколькими вещами, которые не являются вложенными, вы можете использовать это:

function timer(lap){ 
    if(lap) console.log(`${lap} in: ${(performance.now()-timer.prev).toFixed(3)}ms`); 
    timer.prev = performance.now();
}

Аналогичен console.time(), но более прост в использовании, если вам не нужно отслеживать предыдущие таймеры.

Если вам нравится синий цвет из console.time(), вы можете использовать эту строку вместо

console.log(`${lap} in: %c${(performance.now()-timer.prev).toFixed(3)}ms`, 'color:blue');

// Usage: 
timer()              // set the start
// do something 
timer('built')       // logs 'built in: 591.815ms'
// do something
timer('copied')      // logs 'copied in: 0.065ms'
// do something
timer('compared')    // logs 'compared in: 36.41ms'

Поскольку console.time а также performance.now не поддерживаются в некоторых основных браузерах (например, IE10), я создал тонкую утилиту, которая использует лучшие доступные методы. Тем не менее, он не обрабатывает ошибки для ложного использования (вызов End() на неинициализированном таймере).

Используйте его и улучшайте как хотите.

Performance: {
    Timer: {},
    Start: function (name) {
        if (console && console.time) {
            console.time(name);
        } else if (window.performance.now) {
            this.Timer[name] = window.performance.now();
        } else {
            this.Timer[name] = new Date().getTime();
        }
    },
    End: function (name) {
        if (console && console.time) {
            console.timeEnd(name);
        } else {
            var result;
            if (window.performance.now) {
                result = window.performance.now() - this.Timer[name];
            } else {
                result = new Date().getTime() - this.Timer[name];
            }
            console.log(name + ": " + result);
        }
    }
}

Пару месяцев назад я собрал свою собственную подпрограмму, которая рассчитывает время с помощью функции Date.now() - хотя в то время принятым методом, как представляется, был performance.now() - потому что объект производительности еще не доступен (построен -in) в стабильной версии Node.js.

Сегодня я проводил дополнительные исследования и нашел другой метод для определения времени. Так как я также нашел, как использовать это в коде Node.js, я решил поделиться этим здесь.

Следующее объединено с примерами, данными w3c и Node.js:

function functionTimer() {
    performance.mark('start')
    functionToBeTimed()
    performance.mark('end')
    performance.measure('Start to End', 'start', 'end')
    const measure = performance.getEntriesByName('Start to End')[0]
    console.log(measure.duration)
}

НОТА:

Если вы собираетесь использовать performance объект в приложении Node.js, вы должны включить следующее требование: const { performance } = require('perf_hooks')

Спасибо, Ахим Кёльнер, немного расширит ваш ответ:

var t0 = process.hrtime();
//Start of code to measure

//End of code
var timeInMilliseconds = process.hrtime(t0)[1]/1000000; // dividing by 1000000 gives milliseconds from nanoseconds

Пожалуйста, обратите внимание, что вы не должны делать ничего, кроме того, что вы хотите измерить (например, console.log также потребуется время для выполнения и повлияет на тесты производительности).

Обратите внимание, что для измерения времени выполнения асинхронных функций необходимо вставить var timeInMilliseconds = process.hrtime(t0)[1]/1000000; внутри обратного вызова. Например,

var t0 = process.hrtime();
someAsyncFunction(function(err, results) {
var timeInMilliseconds = process.hrtime(t0)[1]/1000000;

});

Используйте console.time(«какая-то метка здесь») перед функцией и console.timeEnd(«здесь какая-то метка») после функции. Это даст время работы функции.

С производительностью

NodeJs: требуется импортировать класс производительности

var time0 = performance.now(); // Store the time at this point into time0

yourFunction();   // The function you're measuring time for 

var time1 = performance.now(); // Store the time at this point into time1

console.log("youFunction took " + (time1 - time0) + " milliseconds to execute");

Использование console.time

console.time('someFunction');

someFunction(); // Whatever is timed goes between the two "console.time"

console.timeEnd('someFunction');

Примечание. Простейшая реализация чистого функционала, метод ES6, никаких дополнительных переменных не требуется, всего 3 строки кода. Обрабатывает синхронизирующие и асинхронные коды, поэтому внешние библиотеки не требуются, работает как в JavaScript, так и в Node JS, может даже использоваться для проверки задержки ваших API.

      // Create one-liner timer function
let [timer, timingMonitor] = [0, () => timer = !timer ? Date.now() : `${Date.now() - timer}ms`]
        
// Initiate timer
timingMonitor();
        
// Your code here
doSomething();
        
// End timer 
console.log(timingMonitor());

// Console output: "102ms", for example 

Секундомер с накопительными циклами

Работает с сервером и клиентом (Node или DOM), использует Performance API. Хорошо, когда у вас много маленьких циклов, например, в функции, вызываемой 1000 раз, которая обрабатывает 1000 объектов данных, но вы хотите увидеть, как каждая операция в этой функции складывается в общую сумму.

Так что этот использует глобальный (одиночный) таймер модуля. То же самое, что и шаблон синглтона класса, чуть проще в использовании, но вы должны поместить его в отдельный stopwatch.js файл.

const perf = typeof performance !== "undefined" ? performance : require('perf_hooks').performance;
const DIGITS = 2;

let _timers = {};

const _log = (label, delta?) => {
    if (_timers[label]) {
        console.log(`${label}: ` + (delta ? `${delta.toFixed(DIGITS)} ms last, ` : '') +
            `${_timers[label].total.toFixed(DIGITS)} ms total, ${_timers[label].cycles} cycles`);
    }
};

export const Stopwatch = {
    start(label) {
        const now = perf.now();
        if (_timers[label]) {
            if (!_timers[label].started) {
                _timers[label].started = now;
            }
        } else {
            _timers[label] = {
                started: now,
                total: 0,
                cycles: 0
            };
        }
    },
    /** Returns total elapsed milliseconds, or null if stopwatch doesn't exist. */
    stop(label, log = false) {
        const now = perf.now();
        if (_timers[label]) {
            let delta;
            if(_timers[label].started) {
                delta = now - _timers[label].started;
                _timers[label].started = null;
                _timers[label].total += delta;
                _timers[label].cycles++;
            }
            log && _log(label, delta);
            return _timers[label].total;
        } else {
            return null;
        }
    },
    /** Logs total time */
    log: _log,
    delete(label) {
        delete _timers[label];
    }
};

Лучший способ будет использовать performance hooks модуль. Хотя нестабильно, вы можете mark конкретные области вашего кода и measure duration между отмеченными областями.

const { performance, PerformanceObserver } = require('perf_hooks');

const measures = []

const obs = new PerformanceObserver(list => measures.push(...list.getEntries()));
obs.observe({ entryTypes: ['measure'] });
const getEntriesByType = cb => cb(measures);

const doSomething = val => {
  performance.mark('beginning of the process');

  val *= 2;

  performance.mark('after multiplication');

  performance.measure('time taken', 'beginning of the process', 'after multiplication');

  getEntriesByType(entries => {
    entries.forEach(entry => console.log(entry));
  })

  return val;
}

doSomething(4);

Попробуй здесь

  1. Чтобы запустить таймер, используйтеconsole.time("myTimer");
  2. Необязательно: чтобы напечатать прошедшее время, используйтеconsole.timeLog("myTimer");
  3. Наконец, чтобы остановить таймер и напечатать последнее время:console.timeEnd("myTimer");

Вы можете прочитать об этом на MDN и в документации Node.js.

Доступно в Chrome, Firefox, Opera и NodeJS. (не в Edge или Internet Explorer).

export default class Singleton {

  static myInstance: Singleton = null;

  _timers: any = {};

  /**
   * @returns {Singleton}
   */
  static getInstance() {
    if (Singleton.myInstance == null) {
      Singleton.myInstance = new Singleton();
    }

    return this.myInstance;
  }

  initTime(label: string) {
    this._timers[label] = Date.now();
    return this._timers[label];
  }

  endTime(label: string) {
    const endTime = Date.now();
    if (this._timers[label]) {
      const delta = endTime - this._timers[label];
      const finalTime = `${label}: ${delta}ms`;
      delete this._timers[label];
      return finalTime;
    } else {
      return null;
    }
  }
}

InitTime, связанный с string,

return Singleton.getInstance().initTime(label); // Returns the time init

return Singleton.getInstance().endTime(label); // Returns the total time between init and end

В моем случае я предпочитаю использовать @ gramar suger и компилировать его с помощью babel.
Проблема этого метода в том, что функция должна быть внутри объекта.

Образец кода JS

function timer() {
    return (target, propertyKey, descriptor) => {
        const start = Date.now();
        let oldFunc = descriptor.value;

        descriptor.value = async function (){
            var result = await oldFunc.apply(this, arguments);
            console.log(Date.now() - start);
            return result;
        }
    }
}

// Util function 
function delay(timeout) {
    return new Promise((resolve) => setTimeout(() => {
        resolve();
    }, timeout));
}

class Test {
    @timer()
    async test(timout) {
        await delay(timout)
        console.log("delay 1");
        await delay(timout)
        console.log("delay 2");
    }
}

const t = new Test();
t.test(1000)
t.test(100)

.babelrc (для babel 6)

 {
    "plugins": [
        "transform-decorators-legacy"
    ]
 }

Базовый пример TypeScript, который поддерживает метки. Вызов start('something')запустит таймер и stop('something')завершит таймер и вернет отформатированную строку, содержащую прошедшее время.

Посмотреть пример Флемса

      /**
 * Mark entries
 */
export const marks: { [id: string]: number } = {};

/**
 * Start timing 
 */
export const start = (id: string) => {
  return Object.assign(marks, {[id]: Date.now() })[id]
}

/**
 * Clear all 
 */
export const clear = () => {
  for (const id in marks) delete marks[id]; 
};

/**
 * Stop timing and return formatted elapsed time
 */
export const stop = (id: string) => {
  const ms = Date.now() - marks[id];
  delete marks[id];
  return ms > 1000 
    ? `${(ms / 1000).toFixed(0)}s ${+ms.toFixed(0).slice(1)}ms` 
    : `${ms.toFixed(0)}ms`;
};

Пример кода экспортирует каждую функцию. Вы можете поместить это в проект и соответственно вызывать методы по умолчанию. asимпорт, например:

      import * as time from './timer.js'

time.start('foo')

// do something

console.log('elapsed time: ' + time.stop('bar'))
const { performance } = require('perf_hooks');

function addUpTo(n) {
  let total = 0;
  for (let i = 1; i <= n; i++) {
    total += i;
  }
  return total;
}


let t1 = performance.now();
addUpTo(1000000000);
let t2 = performance.now();
console.log(`Time elapsed: ${(t2 - t1) / 1000} seconds`);
// Time elapsed: 1.1261566010713577 seconds
console.time('startID') // inbuilt function

myFunction() 

console.timeEnd('startID') // inbuilt function

'startID' -> это уникальный идентификатор для определения области

В приведенном выше коде указано время, затрачиваемое myFunction на выполнение.

Другие вопросы по тегам