ฉันจะวัดเวลาดำเนินการของโค้ด JavaScript ด้วยการโทรกลับได้อย่างไร


319

ฉันมีรหัสจาวาสคริปต์ที่ฉันกำลังใช้งานโดยใช้node.jsล่าม

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
แค่อ่านเวลาเริ่มต้นก่อนที่จะเรียกฐานข้อมูลและเวลาสิ้นสุดภายในโทรกลับ ..
BFil

มีความเป็นไปได้หรือไม่ที่เวลาที่ฐานข้อมูลเสร็จสิ้นการแทรกและเวลาที่ดำเนินการติดต่อกลับไม่เหมือนกันและสิ่งนี้จะแนะนำข้อผิดพลาดในการวัดหรือไม่
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ülUç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 solution แต่อย่างใด?
scravy

31
ใช่มันแม่นยำมากขึ้นและคุณสามารถเก็บผลลัพธ์ไว้ในตัวแปรได้
Dallas Clark

อันนี้ใช้งานได้สำหรับฉันเนื่องจากฉันต้องการโทรหาตัวจับเวลาหลาย ๆ ครั้ง
tbh__

2
ทำไมคุณโทรprocess.hrtime(start)สองครั้ง มีเหตุผลพิเศษไหม?
Sohail Si

1
process.hrtime ([เวลา]) โดยที่ time เป็นพารามิเตอร์ทางเลือกที่ต้องเป็นผลลัพธ์ของการเรียก process.hrtime () ก่อนหน้านี้เพื่อให้แตกต่างกับเวลาปัจจุบัน มันให้ความแตกต่างระหว่างการโทรปัจจุบันและการโทร 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

แปลกใจที่ไม่มีใครพูดถึง แต่ตัวใหม่ในห้องสมุด:

พร้อมใช้งานในโหนด> = 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 ฉันจะอัปเดตเมื่อฉันมีโอกาส!
โคดี้ G

19

สำหรับทุกคนที่ต้องการรับค่าเวลาที่ผ่านไปแทนที่จะเป็นเอาต์พุตคอนโซล

ใช้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;
}

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 ) มันไม่ใช่ความคิดที่ดีที่จะใช้แบบฟอร์มนั้นเพื่อเหตุผลด้านประสิทธิภาพและความสามารถในการอ่าน ฉันชอบบางสิ่งบางอย่าง verbose มากขึ้นดังนั้นจึงเป็นที่ชัดเจนกับผู้อ่าน โปรดดูคำตอบนี้: stackoverflow.com/a/5036460/5114
Mnebuerquo

3
ฉันมักจะใช้var start = process.hrtime(); ... var end = process.hrtime(start);เพื่อให้ได้เวลาที่มีความละเอียดสูง (ถ้าฉันต้องการความแม่นยำในระดับมิลลิวินาทีต่ำกว่า)
Andrey Sidorov

9

คำถามเก่า ๆ แต่สำหรับ 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

[edit] มีวิธีที่ง่ายกว่าในการใช้ 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 คุณสามารถใช้เวลาที่มีอยู่ () และ timeEnd () ได้แล้ว

สำหรับ Azure ให้ใช้สิ่งนี้: https://github.com/manoharreddyporeddy/my-nodejs-notes/blob/master/performance_timers_helper_nodejs_azure_aws.js

เวลาเหล่านี้ () และ timeEnd () ใช้ฟังก์ชัน hrtime () ที่มีอยู่ซึ่งให้ความละเอียดสูงแบบเรียลไทม์

หวังว่านี่จะช่วยได้


0

และอีกตัวเลือกหนึ่งคือการใช้เครื่องมือExpress-Debug :

Express-debug เป็นเครื่องมือในการพัฒนาสำหรับ express มิดเดิลแวร์แบบธรรมดาที่ใช้ในการดีบักเอาต์พุตที่มีประโยชน์ใน html ของคุณในลักษณะที่ไม่มีสิ่งกีดขวาง

มันมีแผงโปรไฟล์อย่างสะดวก:

เวลาการประมวลผลการร้องขอทั้งหมด มิดเดิลแวร์, พารามิเตอร์และการกำหนดเส้นทาง

ด้วย เพื่อเพิ่มคำตอบข้างต้นคุณสามารถตรวจสอบคำตอบนี้เพื่อเปิดใช้งานรหัสการทำโปรไฟล์สำหรับสภาพแวดล้อมการพัฒนาเท่านั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.