2012-05-16 2 views
213

У меня есть часть кода javascript, которую я выполняю с помощью интерпретатора node.js.Как измерить время выполнения кода javascript с обратными вызовами

for(var i = 1; i < LIMIT; i++){ 
    db.users.save({id : i, name : "MongoUser [" + i + "]"}, function(err, saved) { 
      if(err || !saved) console.log("Error"); 
      else console.log("Saved"); 
    }); 
} 

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

+6

Просто прочитайте время начала перед вызовом db и время окончания INSIDE обратного вызова. – BFil

+0

Существует вероятность того, что время, в течение которого БД заканчивает вставку и время выполнения обратного вызова, не совпадает, и это ввести ошибку в измерение? – Stormshadow

+1

Нет, вам не стоит беспокоиться об этом, если код библиотеки db хорошо разработан и не обрабатывает какую-либо другую операцию перед запуском обратного вызова, вы должны получить хорошую оценку. Вы также можете профилировать вставку, помещая метки времени внутри кода библиотеки, где фактически выполняется вставка, а не ваша собственная, но, опять же, я бы не стал беспокоиться об этом. – BFil

ответ

499

Используйте Node.js console.time() и console.timeEnd():

var i; 
console.time("dbsave"); 

for(i = 1; i < LIMIT; i++){ 
    db.users.save({id : i, name : "MongoUser [" + i + "]"}, end); 
} 

end = function(err, saved) { 
    console.log((err || !saved)?"Error":"Saved"); 
    if(--i === 1){console.timeEnd("dbsave");} 
}; 
+19

Чистое и встроенное решение для узла. –

+22

> Я хочу знать, как измерить время, затрачиваемое этими операциями вставки db. --- console.timeEnd ("dbsave") просто выводит на консоль время. Вы не можете использовать это дальше и менее гибко. Если вам нужно фактическое значение времени, как в исходном вопросе, вы не можете использовать console.timeEnd («dbsave») – gogaman

+0

@gogaman, это хороший момент, поскольку вы не можете захватить вывод из console.timeEnd(). Может быть, было бы полезно подключить вывод к файлу и использовать оттуда? –

2

Вы можете дать Benchmark.js попытку. Он поддерживает множество платформ среди них также node.js.

+5

Было бы неплохо, если бы вы могли добавить пример использования benchmark.js для этого варианта использования. – Petah

15
var start = +new Date(); 
var counter = 0; 
for(var i = 1; i < LIMIT; i++){ 
    ++counter; 
    db.users.save({id : i, name : "MongoUser [" + i + "]"}, function(err, saved) { 
      if(err || !saved) console.log("Error"); 
      else console.log("Saved"); 
      if (--counter === 0) 
      { 
       var end = +new Date(); 
       console.log("all users saved in " + (end-start) + " milliseconds"); 
      } 
    }); 
} 
+4

Мне пришлось искать синтаксис «+ new Date()», чтобы понять, что это значит. Согласно комментариям к этому ответу (http://stackoverflow.com/a/221565/5114), не рекомендуется использовать эту форму по соображениям производительности, а также для удобочитаемости. Я предпочитаю что-то более подробное, поэтому читателю это понятно. Также см. Этот ответ: http://stackoverflow.com/a/5036460/5114 – Mnebuerquo

+2

Я часто использую 'var start = process.hrtime(); ... var end = process.hrtime (start); 'для получения времени высокого разрешения (если мне нужно ожидать точности субмиллисекунда) –

0

Я рекомендую попробовать NodeTime, который, кажется, хорошо подходит для того, что вы пытаетесь сделать.

+1

Почему бы не привести пример кода тоже, это было бы полезно! :-) –

+0

Хорошо, что ответ был дан четыре с половиной года назад, а NodeTime больше не думаю. Мир Node.JS очень быстро движется - интересно, что принятый ответ был дан через 12 месяцев после того, как был задан вопрос! –

158

Существует метод, который предназначен для этого. Выезд process.hrtime();.

Итак, я в основном ставил это в верхней части моего приложения.

var start = process.hrtime(); 

var elapsed_time = function(note){ 
    var precision = 3; // 3 decimal places 
    var elapsed = process.hrtime(start)[1]/1000000; // divide by a million to get nano to milli 
    console.log(process.hrtime(start)[0] + " s, " + elapsed.toFixed(precision) + " ms - " + note); // print message + time 
    start = process.hrtime(); // reset the timer 
} 

Затем я использую его, чтобы узнать, как долго выполняются функции. Вот простой пример, который печатает содержимое текстового файла с именем «output.txt»:

var debug = true; 
http.createServer(function(request, response) { 

    if(debug) console.log("----------------------------------"); 
    if(debug) elapsed_time("recieved request"); 

    var send_html = function(err, contents) { 
     if(debug) elapsed_time("start send_html()"); 
     response.writeHead(200, {'Content-Type': 'text/html' }); 
     response.end(contents); 
     if(debug) elapsed_time("end send_html()"); 
    } 

    if(debug) elapsed_time("start readFile()"); 
    fs.readFile('output.txt', send_html); 
    if(debug) elapsed_time("end readFile()"); 

}).listen(8080); 

Вот быстрый тест, который вы можете запустить в терминале (BASH оболочки):

for i in {1..100}; do echo $i; curl http://localhost:8080/; done 
+2

это, что превосходит решение console.time в любом случае? – scravy

+21

Да, это намного точнее, и вы можете сохранить результат в переменной –

+0

. Это работает для меня, так как я хотел вызвать таймер несколько раз –

31

console.time('label'), ссылающегося будет записывать текущее время в миллисекундах, а потом вызывая console.timeEnd('label') воли ди вывести продолжительность с этой точки.

Время в миллисекундах будет автоматически печататься вместе с этикеткой, так что вам не придется делать отдельный вызов console.log для печати этикетки:

console.time('test'); 
//some code 
console.timeEnd('test'); //Prints something like that-> test: 11374.004ms 

Для получения дополнительной информации см Mozilla's developer docs on console.time.

2

Вы также можете попробовать exectimer. Это дает вам обратную связь, как:

var t = require("exectimer"); 

var myFunction() { 
    var tick = new t.tick("myFunction"); 
    tick.start(); 
    // do some processing and end this tick 
    tick.stop(); 
} 

// Display the results 
console.log(t.timers.myFunction.duration()); // total duration of all ticks 
console.log(t.timers.myFunction.min()); // minimal tick duration 
console.log(t.timers.myFunction.max()); // maximal tick duration 
console.log(t.timers.myFunction.mean()); // mean tick duration 
console.log(t.timers.myFunction.median()); // median tick duration 

[править] Существует еще более простой способ теперь использовать exectimer, потому что теперь он может обернуть код для измерения. Ваш код может быть обернут следующим образом:

var t = require('exectimer'), 
Tick = t.Tick; 

for(var i = 1; i < LIMIT; i++){ 
    Tick.wrap(function saveUsers(done) { 
     db.users.save({id : i, name : "MongoUser [" + i + "]"}, function(err, saved) { 
      if(err || !saved) console.log("Error"); 
      else console.log("Saved"); 
      done(); 
     }); 
    }); 
} 

// Display the results 
console.log(t.timers.myFunction.duration()); // total duration of all ticks 
console.log(t.timers.saveUsers.min()); // minimal tick duration 
console.log(t.timers.saveUsers.max()); // maximal tick duration 
console.log(t.timers.saveUsers.mean()); // mean tick duration 
console.log(t.timers.saveUsers.median()); // median tick duration 
7

Старый вопрос, но для простого API и легкого решения; вы можете использовать perfy, который использует высокое разрешение в реальном времени (process.hrtime) внутри.

var perfy = require('perfy'); 

function end(label) { 
    return function (err, saved) { 
     console.log(err ? 'Error' : 'Saved'); 
     console.log(perfy.end(label).time); // <——— result: seconds.milliseconds 
    }; 
} 

for (var i = 1; i < LIMIT; i++) { 
    var label = 'db-save-' + i; 
    perfy.start(label); // <——— start and mark time 
    db.users.save({ id: i, name: 'MongoUser [' + i + ']' }, end(label)); 
} 

Обратите внимание, что каждый раз, когда perfy.end(label) называется, что экземпляр автоматически уничтожается.

Disclosure: Написал этот модуль, вдохновленный D.Deriso's answer. Документы here.

0

И еще один вариант заключается в использовании express-debug инструмента:

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

Это удобно предлагает профилирование панель:

общее время обработки REQ. промежуточное программное обеспечение, параметры и сроки маршрута.

Также. чтобы добавить к приведенным выше ответам, вы можете проверить this answer, чтобы включить только код профилирования для среды разработки.

6

Для тех, кто хочет получить время, истекшее значение вместо консольного вывода:

использование process.hrtime() как @ D.Deriso предложение, ниже мой простой подход:

function functionWantToMeasure() { 
    var startTime = process.hrtime(); 
    //do some task... 
    var elapsedSeconds = parseHrtimeToSeconds(process.hrtime(startTime)); 
    console.log('functionWantToMeasure takes ' + elapsedSeconds + 'seconds'); 
} 

function parseHrtimeToSeconds(hrtime) { 
    var seconds = (hrtime[0] + (hrtime[1]/1e9)).toFixed(3); 
    return seconds; 
} 
1

У меня было то же самое при переходе от AWS к Azure

Для экспресс & aws, вы уже можете использовать существующее время() и t imeEnd()

Для Azure, используйте: https://github.com/manoharreddyporeddy/my-nodejs-notes/blob/master/performance_timers_helper_nodejs_azure_aws.js

Это время() и timeEnd() использовать функцию существующей hrtime(), которые дают с высоким разрешением в режиме реального времени.

Надеюсь, это поможет.