400

我有一段使用node.js解释器执行的 JavaScript 代码。

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

如何测量这些数据库插入操作所花费的时间?我可以计算这段代码前后日期值的差异,但由于代码的异步性质,这是不正确的。

4

13 回答 13

862

使用 Node.jsconsole.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");}
};
于 2013-08-25T09:39:44.447 回答
248

有一种为此设计的方法。查看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 shell)中运行的快速测试:

for i in {1..100}; do echo $i; curl http://localhost:8080/; done
于 2013-01-27T19:26:32.733 回答
125

调用console.time('label')将以毫秒为单位记录当前时间,然后稍后调用console.timeEnd('label')将显示从该点开始的持续时间。

以毫秒为单位的时间将自动打印在标签旁边,因此您不必单独调用 console.log 来打印标签:

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

有关详细信息,请参阅Mozilla 的开发人员文档console.time

于 2014-08-03T14:28:26.983 回答
39

令人惊讶的是没有人提到新的内置库:

在 Node >= 8.5 中可用,并且应该在 Modern Browsers 中

https://developer.mozilla.org/en-US/docs/Web/API/Performance

https://nodejs.org/docs/latest-v8.x/api/perf_hooks.html#

节点 8.5 ~ 9.x (Firefox, Chrome)

// const { performance } = require('perf_hooks'); // enable for node
const delay = time => new Promise(res=>setTimeout(res,time))
async function doSomeLongRunningProcess(){
  await delay(1000);
}
performance.mark('A');
(async ()=>{
  await doSomeLongRunningProcess();
  performance.mark('B');
  performance.measure('A to B', 'A', 'B');
  const measure = performance.getEntriesByName('A to B')[0];
  // firefox appears to only show second precision.
  console.log(measure.duration);
  // apparently you should clean up...
  performance.clearMarks();
  performance.clearMeasures();         
  // Prints the number of milliseconds between Mark 'A' and Mark 'B'
})();

https://repl.it/@CodyGeisler/NodeJsPerformanceHooks

节点 12.x

https://nodejs.org/docs/latest-v12.x/​​api/perf_hooks.html

const { PerformanceObserver, performance } = require('perf_hooks');
const delay = time => new Promise(res => setTimeout(res, time))
async function doSomeLongRunningProcess() {
    await delay(1000);
}
const obs = new PerformanceObserver((items) => {
    console.log('PerformanceObserver A to B',items.getEntries()[0].duration);
      // apparently you should clean up...
      performance.clearMarks();
      // performance.clearMeasures(); // Not a function in Node.js 12
});
obs.observe({ entryTypes: ['measure'] });

performance.mark('A');

(async function main(){
    try{
        await performance.timerify(doSomeLongRunningProcess)();
        performance.mark('B');
        performance.measure('A to B', 'A', 'B');
    }catch(e){
        console.log('main() error',e);
    }
})();
于 2018-06-29T17:13:20.840 回答
31

对于任何想要获取经过时间的值而不是控制台输出的人:

使用process.hrtime()作为@D.Deriso 的建议,下面是我更简单的方法:

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

function parseHrtimeToSeconds(hrtime) {
    var seconds = (hrtime[0] + (hrtime[1] / 1e9)).toFixed(3);
    return seconds;
}
于 2017-05-19T12:08:11.173 回答
17
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");
          }
    });
}
于 2012-05-16T12:54:13.510 回答
10

老问题,但对于简单的 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)调用时,该实例都会自动销毁。

披露:受D.Deriso 的回答启发,编写了这个模块。文档在这里

于 2015-10-12T02:17:35.807 回答
3

您也可以尝试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

[编辑] 现在有一种更简单的方法来使用 exectime。您的代码可以像这样包装:

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
于 2014-08-05T13:09:32.627 回答
2

你可以试试Benchmark.js 。它支持许多平台,其中还有 node.js。

于 2012-05-16T12:30:23.453 回答
2

我为此设计了一个简单的方法,使用console.time()console.timeEnd()

测量函数定义
function measureRunningTime(func,...args){
    const varToString = varObj => Object.keys(varObj)[0]
    const displayName = func.name || varToString({ func })
    console.time(displayName)
    func(...args)
    console.timeEnd(displayName)
}

要使用它,请传递不带参数、绑定参数或带参数的函数作为以下参数。

例子:

假设我想检查最简单的搜索算法的运行时间 - SimpleSearch:
测量函数定义(您的代码在这里)
const simpleSearch = (array = [1,2,3] ,item = 3) => {
    for(let i = 0; i< array.length; i++){
        if (array[i] === item) return i;
    }
    return -1
}

不带参数的实现
measureRunningTime(simpleSearch) 
//Prints something like that-> simpleSearch: 0.04ms
使用 .bind() 的参数实现
const array = [1,2,3]
const item = 3
measureRunningTime(simpleSearch.bind(null, array, item))
//Prints something like that-> bound simpleSearch: 0.04ms
不使用 .bind() 的参数实现
const array = [1,2,3]
const item = 3
measureRunningTime(simpleSearch, array, item)
//Prints something like that-> simpleSearch: 0.04ms

-> 注意!!这个实现远非完美——例如没有错误处理——但它可以用来检查简单算法的运行时间,此外,我不是一个有经验的程序员,所以对一切都持保留态度

于 2021-11-17T13:06:28.607 回答
1

从 AWS 迁移到 Azure 时我遇到了同样的问题

对于 express 和 aws,您已经可以使用现有的 time() 和 timeEnd()

对于 Azure,请使用: https ://github.com/manoharreddyporeddy/my-nodejs-notes/blob/master/performance_timers_helper_nodejs_azure_aws.js

这些 time() 和 timeEnd() 使用现有的 hrtime() 函数,提供高分辨率的实时。

希望这可以帮助。

于 2017-11-07T06:03:34.970 回答
1

您可以使用wrapper函数轻松报告任何现有函数的执行时间。

包装器用于扩展现有函数以在现有函数执行之前和之后执行某些操作 - 并且是组合逻辑的便捷方式。

这是使用withDurationReporting包装器的示例:

// without duration reporting
const doSomethingThatMayTakeAWhile = async (someArg: string, anotherArg: number) => { 
  /** your logic goes here */
}

// with duration reporting
const doSomethingThatMayTakeAWhileWithReporting = withDurationReporting(
  'doSomethingThatMayTakeAWhile', 
  doSomethingThatMayTakeAWhile
);
// note: you can define the function with duration reporting directly, too
const doSomethingThatMayTakeAWhile = withDurationReporting(
  'doSomethingThatMayTakeAWhile', 
  async (someArg: string, anotherArg: number) => { 
    /** your logic goes here */
  }
)

这是包装器本身:

import { hrtime } from 'process';

const roundToHundredths = (num: number) => Math.round(num * 100) / 100; // https://stackoverflow.com/a/14968691/3068233

/**
 * a wrapper which reports how long it took to execute a function, after the function completes
 */
export const withDurationReporting = <R extends any, T extends (...args: any[]) => Promise<R>>(
  title: string,
  logic: T,
  options: {
    reportingThresholdSeconds: number;
    logMethod: (message: string, metadata?: Record<string, any>) => void;
  } = {
    reportingThresholdSeconds: 1, // report on anything that takes more than 1 second, by default
    logMethod: console.log, // log with `console.log` by default
  }, 
) => {
  return (async (...args: Parameters<T>): Promise<R> => {
    const startTimeInNanoseconds = hrtime.bigint();
    const result = await logic(...args);
    const endTimeInNanoseconds = hrtime.bigint();
    const durationInNanoseconds = endTimeInNanoseconds - startTimeInNanoseconds;
    const durationInSeconds = roundToHundredths(Number(durationInNanoseconds) / 1e9); // https://stackoverflow.com/a/53970656/3068233
    if (durationInSeconds >= options.reportingThresholdSeconds)
      options.logMethod(`${title} took ${durationInSeconds} seconds to execute`, { title, durationInSeconds });
    return result;
  }) as T;
};
于 2021-09-07T09:36:00.603 回答
0

我需要这是累积的,并衡量不同的东西。
构建了这些功能:

function startMeasuring(key) {
  measureTimers[key] = process.hrtime();
}

function stopMeasuring(key) {
  if (!measures[key]) {
    measures[key] = 0;
  }

  let hrtime = process.hrtime(measureTimers[key]);
  measures[key] += hrtime[0] + hrtime[1] / 1e9;
  measureTimers[key] = null;
}

用法:

startMeasuring("first Promise");
startMeasuring("first and second Promises");
await new Promise((resolve) => {
  setTimeout(resolve, 1400);
});
stopMeasuring("first Promise");
stopMeasuring("first and second Promises");

startMeasuring("first and second Promises");
await new Promise((resolve) => {
  setTimeout(resolve, 600);
});
stopMeasuring("first and second Promises");

console.log("Measure Results", measures); 
/*
Measusre Results {
  setting: 0.00002375,
  'first Promise': 1.409392916,
  'first and second Promise': 2.015160376
}
*/
于 2021-07-05T13:10:35.033 回答