콜백을 사용하여 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.