콜백을 사용하여 JavaScript 코드의 실행 시간을 어떻게 측정합니까?


319

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");
    }
  });
}

이러한 데이터베이스 삽입 작업에 걸리는 시간을 어떻게 측정 할 수 있습니까? 이 코드 조각 전후에 날짜 값의 차이를 계산할 수 있지만 코드의 비동기 특성으로 인해 올바르지 않습니다.


8
db 호출 전의 시작 시간과 콜백 내부의 종료 시간을
읽으십시오

DB가 인서트를 완료하는 시간과 콜백이 실행되는 시간이 같지 않아 측정에 오류가 발생할 가능성이 있습니까?
Stormshadow

1
아니요, DB 라이브러리 코드가 잘 설계되어 콜백을 시작하기 전에 다른 작업을 처리하지 않으면 걱정할 필요가 없습니다. 삽입이 실제로 수행되는 라이브러리 코드 내에 타임 스탬프를 삽입하는 대신 삽입을 프로파일 링 할 수도 있지만, 걱정하지 않아도됩니다.
BFil

NodeTime 을 시도하는 것이 좋습니다 .이 작업은 수행하려는 작업에 적합합니다.
Julian Knight

나는 timerlog비슷 console.time()하지만 추가 기능으로 썼다 . github.com/brillout/timerlog
brillout

답변:


718

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");}
};

31
노드를위한 깨끗하고 내장 된 솔루션.
Behlül Uçar

45
>이 DB 삽입 작업에 걸리는 시간을 측정하는 방법을 알고 싶습니다. --- console.timeEnd ( "dbsave")는 타이밍을 콘솔로 출력합니다. 더 이상 사용할 수 없으며 유연성이 떨어집니다. 원래 질문에서와 같이 실제 타이밍 값이 필요한 경우 console.timeEnd ( "dbsave")
gogaman

@ gogaman 이것은 console.timeEnd ()에서 출력을 캡처 할 수 없기 때문에 좋은 지적입니다. 아마도 출력을 파일로 파이프하고 거기서 활용하는 것이 유용 할 수 있습니까?
Doug Molineux

5
아래 답변에서 console.time ()과 process.hrtime ()의 차이점은 무엇입니까?
노란색 성자

3
실행 시간이 인쇄되어 이제 새로운 사용자가되도록 메모를 추가 할 가치가 있습니다.
janko-m

208

이를 위해 설계된 방법이 있습니다. 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

3
어떤 식 으로든 console.time 솔루션보다 우수합니까?
scravy

31
그렇습니다. 훨씬 정확하고 결과를 변수에 저장할 수 있습니다
Dallas Clark

타이머를 여러 번 호출하고 싶었 기 때문에 이것은 나를 위해
tbh__

2
process.hrtime(start)두 번 전화 해요? 특별한 이유가 있습니까?
Sohail Si

1
process.hrtime ([time]). 여기서 시간은 현재 시간으로 diff하기위한 이전 process.hrtime () 호출의 결과 여야하는 선택적 매개 변수입니다. 현재 통화와 이전 시간 통화의 차이를 나타냅니다.
Nilesh Jain

72

호출하면 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 참조하십시오 .


답변에 무엇이 추가 됩니까?
Dan Dascalescu

1
허용 대답은 내 코드를 사용하는 내 대답 한 후 수정
jfcorugedo

24

아직 새로운 내장 라이브러리를 언급 한 사람이 아무도 없습니다.

Node> = 8.5에서 사용 가능하며 Modern Browers에 있어야합니다.

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);
  performance.clearMeasures(); // apparently you should remove entries...
  // Prints the number of milliseconds between Mark 'A' and Mark 'B'
})();

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

노드 10.x

https://nodejs.org/docs/latest-v10.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);
    performance.clearMarks();
});
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);
    }
})();

TypeError: performance.getEntriesByName is not a function노드 v10.4.1에서 제공
Jeremy Thille

온라인에서 실행할 수 있도록 예제를 만들었습니다. 노드 9.7.1입니다. v10.4.1에서 작동하지 않으면 무엇이 변경 될지 궁금합니다!
코디 G

1
Stability: 1 - Experimental아마도? :) nodejs.org/docs/latest-v8.x/api/…
Jeremy Thille

예, 확실히 바뀌 었습니다. v10에는 새로운 관찰자가 있으며 nodejs.org/docs/latest-v10.x/api/documentation.html 에서 문서를 볼 수 있습니다 . 기회가 생기면 업데이트하겠습니다!
Cody G

19

누구나 콘솔 출력 대신 시간 경과 값을 얻으려고합니다.

@ D.Deriso 제안으로 process.hrtime () 을 사용하십시오 . 아래는 더 간단한 접근법입니다.

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;
}

16
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");
          }
    });
}

5
그 의미를 알아 내기 위해 구문 '+ new Date ()'를 찾아야했습니다. 이 답변에 대한 의견 ( stackoverflow.com/a/221565/5114 ) 에 따르면 가독성뿐만 아니라 성능상의 이유로 해당 양식을 사용하는 것은 좋지 않습니다. 나는 조금 더 장황한 것을 선호하므로 독자에게는 더 명확합니다. 또한이 답변을 참조하십시오 : stackoverflow.com/a/5036460/5114
Mnebuerquo

3
내가 자주 사용하는 var start = process.hrtime(); ... var end = process.hrtime(start);(내가 서브 밀리 초 정확도를 기대해야하는 경우) 고해상도 시간을 얻을
안드레이 시도 로프

9

오래된 API이지만 간단한 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의 답변 에서 영감을 얻은이 모듈을 작성했습니다 . 여기에 문서가 있습니다 .


2

당신은 줄 수 Benchmark.js을 시도합니다. node.js 중에서도 많은 플랫폼을 지원합니다.


11
이 사용 사례에 대해 benchmark.js를 사용하는 방법의 예를 추가 할 수 있다면 좋을 것입니다.
Petah

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

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 () 함수를 사용하여 고해상도 실시간을 제공합니다.

도움이 되었기를 바랍니다.


0

또 다른 옵션은 express-debug 도구 를 사용하는 것입니다 .

express-debug는 express를위한 개발 도구입니다. 유용한 디버깅 출력을 방해받지 않는 방식으로 HTML에 삽입하는 간단한 미들웨어입니다.

편리하게 프로파일 링 패널을 제공합니다.

총 요청 처리 시간. 미들웨어, 매개 변수 및 경로 타이밍.

또한. 위의 답변에 추가하려면 이 답변 을 확인 하여 개발 환경에서만 프로파일 링 코드를 활성화 할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.