Làm cách nào để đo thời gian thực thi mã JavaScript bằng các cuộc gọi lại?


319

Tôi có một đoạn mã JavaScript mà tôi đang thực thi bằng trình node.jsthông dịch.

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

Làm thế nào tôi có thể đo thời gian thực hiện bởi các hoạt động chèn cơ sở dữ liệu này? Tôi có thể tính toán sự khác biệt của các giá trị ngày sau và trước đoạn mã này nhưng điều đó sẽ không chính xác vì tính chất không đồng bộ của mã.


8
Chỉ cần đọc thời gian bắt đầu trước cuộc gọi db và thời gian kết thúc bên trong cuộc gọi lại ..
BFil

Có khả năng thời gian DB hoàn thành việc chèn và thời gian thực hiện cuộc gọi lại không giống nhau và điều này sẽ gây ra lỗi trong phép đo?
Stormshadow

1
Không, bạn không nên lo lắng về điều đó, nếu mã thư viện db được thiết kế tốt và không xử lý bất kỳ hoạt động nào khác trước khi thực hiện cuộc gọi lại, bạn sẽ có được một biện pháp tốt. Bạn cũng có thể cấu hình chèn bằng cách đặt dấu thời gian bên trong mã thư viện nơi thực hiện thao tác chèn, thay vì chèn của bạn, nhưng, một lần nữa, tôi sẽ không lo lắng về điều đó
BFil

Tôi khuyên bạn nên thử NodeTime có vẻ phù hợp với những gì bạn đang cố gắng thực hiện.
Julian Knight

Tôi đã viết timerlogtương tự console.time()nhưng với các tính năng bổ sung; github.com/brillout/timerlog
sáng chói

Câu trả lời:


718

Sử dụng 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
Làm sạch và tích hợp giải pháp cho nút.
Behlül Uçar

45
> Tôi muốn biết cách đo thời gian thực hiện bởi các hoạt động chèn db này. --- console.timeEnd ("dbsave") chỉ xuất ra để điều khiển thời gian. Bạn không thể sử dụng nó thêm nữa và kém linh hoạt. Nếu bạn cần giá trị thời gian thực tế, như trong câu hỏi ban đầu, bạn không thể sử dụng console.timeEnd ("dbsave")
gogaman

@gogaman đây là một điểm tốt, vì bạn không thể nắm bắt được đầu ra từ console.timeEnd (). Có lẽ nó có thể hữu ích để dẫn đầu ra thành một tập tin và sử dụng từ đó?
Doug Molineux

5
Vậy sự khác biệt giữa console.time () và process.hrtime () trong câu trả lời dưới đây là gì?
thánh vàng

3
Sẽ đáng để thêm một lưu ý rằng thời gian thực hiện sau đó được in ra, chỉ để người dùng mới bây giờ.
janko-m

208

Có một phương pháp được thiết kế cho việc này. Kiểm tra process.hrtime (); .

Vì vậy, về cơ bản, tôi đặt nó ở đầu ứng dụng của tôi.

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
}

Sau đó, tôi sử dụng nó để xem các chức năng mất bao lâu. Đây là một ví dụ cơ bản in nội dung của tệp văn bản có tên là "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);

Đây là một thử nghiệm nhanh, bạn có thể chạy trong một thiết bị đầu cuối (BASH shell):

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

3
Nó vượt trội so với giải pháp console.time theo cách nào?
cặn bã

31
Đúng, nó chính xác hơn rất nhiều và bạn có thể lưu trữ kết quả trong một biến
Dallas Clark

Cái này hoạt động với tôi, vì tôi muốn gọi bộ hẹn giờ nhiều lần
tbh__

2
Tại sao bạn gọi process.hrtime(start)hai lần? Có một lý do cụ thể cho nó?
Sohail Si

1
process.hrtime ([time]), trong đó thời gian là một tham số tùy chọn phải là kết quả của một cuộc gọi process.hrtime () trước đó khác với thời gian hiện tại. Nó cho sự khác biệt giữa cuộc gọi hiện tại và cuộc gọi giờ trước đó.
Nilesh Jain

72

Gọi console.time('label')sẽ ghi lại thời gian hiện tại tính bằng mili giây, sau đó gọi sau console.timeEnd('label')sẽ hiển thị thời lượng từ thời điểm đó.

Thời gian tính bằng mili giây sẽ được tự động in cùng với nhãn, vì vậy bạn không phải thực hiện một cuộc gọi riêng đến console.log để in nhãn:

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

Để biết thêm thông tin, hãy xem tài liệu dành cho nhà phát triển của Mozillaconsole.time .



1
Câu trả lời được chấp nhận đã được sửa đổi sau khi câu trả lời của tôi sử dụng mã của tôi
jfcorugedo

24

Ngạc nhiên là không có ai đề cập đến các thư viện mới được xây dựng:

Có sẵn trong Nút> = 8,5 và phải có trong Máy phát điện hiện đại

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

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

Nút 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

Nút 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);
    }
})();

Cung cấp cho tôi TypeError: performance.getEntriesByName is not a functiontrong Node v10.4.1
Jeremy Thille

Tôi đã làm ví dụ để bạn có thể chạy nó trực tuyến. Đó là nút 9.7.1. Nếu nó không hoạt động trong v10.4.1 thì tôi tự hỏi điều gì có thể thay đổi!
Cody

1
Stability: 1 - Experimentalcó lẽ? :) nodejs.org/docs/latest-v8.x/api/ Kẻ
Jeremy Thille

Vâng chắc chắn nó đã thay đổi. Có một người quan sát mới trong v10, bạn có thể xem các tài liệu tại nodejs.org/docs/latest-v10.x/api/documentation.html . Tôi sẽ cập nhật khi có cơ hội!
Cody

19

Đối với bất cứ ai muốn có được giá trị thời gian trôi qua thay vì đầu ra giao diện điều khiển:

sử dụng process.hrtime () như đề xuất @ D.Deriso, dưới đây là cách tiếp cận đơn giản hơn của tôi:

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
Tôi đã phải tìm kiếm cú pháp '+ Ngày mới ()' để tìm hiểu điều đó có nghĩa là gì. Theo nhận xét về câu trả lời này ( stackoverflow.com/a/221565/5114 ), không nên sử dụng biểu mẫu đó vì lý do hiệu suất cũng như khả năng đọc. Tôi thích một cái gì đó dài dòng hơn một chút để nó rõ ràng hơn cho người đọc. Cũng xem câu trả lời này: stackoverflow.com/a/5036460/5114
Mnebuerquo

3
Tôi thường sử dụng var start = process.hrtime(); ... var end = process.hrtime(start);để có được thời gian độ phân giải cao (nếu tôi cần mong đợi độ chính xác của mili giây)
Andrey Sidorov

9

Câu hỏi cũ nhưng cho một giải pháp API đơn giản và trọng lượng nhẹ; bạn có thể sử dụng perfy sử dụng thời gian thực độ phân giải cao ( process.hrtime) bên trong.

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

Lưu ý rằng mỗi lần perfy.end(label)được gọi, thể hiện đó sẽ tự động bị hủy.

Tiết lộ: Đã viết mô-đun này, lấy cảm hứng từ câu trả lời của D.Deriso . Tài liệu ở đây .


2

Bạn có thể thử dùng Benchmark.js . Nó hỗ trợ nhiều nền tảng trong số đó cũng là node.js.


11
Sẽ tốt hơn nếu bạn có thể thêm một ví dụ về cách sử dụng điểm chuẩn.js cho trường hợp sử dụng này.
Petah

2

Bạn cũng có thể thử exectimer . Nó cung cấp cho bạn thông tin phản hồi như:

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

[sửa] Bây giờ thậm chí còn có một cách đơn giản hơn để sử dụng exectimer bởi vì bây giờ nó có thể bọc mã cần đo. Mã của bạn có thể được gói như thế này:

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

Tôi gặp vấn đề tương tự khi chuyển từ AWS sang Azure

Đối với express & aws, bạn đã có thể sử dụng, time time () và timeEnd ()

Đối với Azure, hãy sử dụng cái này: https://github.com/manoharreddyporeddy/my-nodejs-notes/blob/master/performance_timftimercper_nodejs_azure_aws.js

Những time () và timeEnd () này sử dụng hàm hrtime () hiện có, cho thời gian thực độ phân giải cao.

Hi vọng điêu nay co ich.


0

Và một tùy chọn khác là sử dụng công cụ gỡ lỗi nhanh :

express-debug là một công cụ phát triển cho express. Đó là phần mềm trung gian đơn giản đưa đầu ra gỡ lỗi hữu ích vào html của bạn, theo cách không gây cản trở.

Nó thuận tiện cung cấp một bảng điều khiển hồ sơ:

tổng thời gian xử lý req. phần mềm trung gian, param, và định thời lộ trình.

Cũng thế. để thêm vào các câu trả lời ở trên, bạn có thể kiểm tra câu trả lời này để chỉ bật bất kỳ mã hồ sơ nào cho môi trường phát triển.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.