引言
項目需要每隔一段時間運行某個方法,JS提供了兩種方式實現定時功能,但我們都知道JS定時其實并不靠譜,現在就簡單進行測試。
- 使用MongoDB作為數據庫存放每次調用的時間,每一條記錄為
{ type: 'setTimeout/setInterval', time: new Date().getTime() }
- 同時使用setTimeout和setInterval定時向MongoDB寫入記錄
- 分別讀取它們寫入的記錄,分析time得出總延遲、平均時間、極差、平均差等值。
實現代碼
/**
* 測試timeout和interval的穩定性
*/
var MongoClient = require('mongodb').MongoClient;
var Server = require('mongodb').Server;
var CONF_DB = require('../config.js').DB;
var collectionTickTest = null;
var setIntervalIndex = 0;
var setTimeoutIndex = 0;
var interval = 1000;
function runTest() {
if (!collectionTickTest) return;
console.info('tickTest start');
setInterval(function(){
collectionTickTest.insert({
type: 'setInterval',
time: new Date().getTime(),
index: ++setIntervalIndex
}, function(err, results) {
if (err) {
console.error('insert fail: ' + err, err);
}
});
}, interval);
var timeoutInsert = function() {
collectionTickTest.insert({
type: 'setTimeout',
time: new Date().getTime(),
index: ++setTimeoutIndex
}, function(err, results) {
if (err) {
console.error('insert fail: ' + err, err);
}
})
setTimeout(timeoutInsert, interval);
}
setTimeout(timeoutInsert, interval);
}
function analysis (result) {
var count = result.length;
console.log('count: ' + count);
// 總差
var sumDiff = (result[count - 1].time - result[0].time) - count * interval;
console.log('sumDiff: ' + sumDiff);
// 平均值
var average = (result[count - 1].time - result[0].time) / count;
console.log('average: ' + average);
// 每個值
var individual = [];
// 極差
var max = interval, min = interval;
// 方差
var variance = 0;
for (var i = 0; i < count -1; i++) {
individual.push(result[i + 1].time - result[i].time);
if (individual[i] > max) {
max = individual[i];
} else if (individual[i] < min) {
min = individual[i];
}
variance += Math.pow((individual[i] - average), 2);
}
console.log('max: ' + max + ', min: ' + min + ', maxDiff: ' + (max -min));
console.log('variance: ' + (variance / count))
}
function analysisSetInterval () {
if (!collectionTickTest) return;
console.info('tickTest analysis setInterval');
collectionTickTest.find({
type: 'setInterval'
}).toArray(function(err, result){
if (err) {
console.error('find setInterval result fail: ' + err, err);
} else {
analysis(result);
}
});
}
function analysisSetTimeout () {
if (!collectionTickTest) return;
console.info('tickTest analysis setTimeout');
collectionTickTest.find({
type: 'setTimeout'
}).toArray(function(err, result){
if (err) {
console.error('find setTimeout result fail: ' + err, err);
} else {
analysis(result);
}
});
}
var constr = 'mongodb://' + CONF_DB.user + ':' + CONF_DB.password + '@' + CONF_DB.host + ':' + CONF_DB.port + '/' + CONF_DB.db;
MongoClient.connect(constr, function(err, con) {
if (err) {
console.error('Connect fail: ' + err, err)
} else {
var db = con.db(CONF_DB.db);
if (db) {
db.authenticate(CONF_DB.user, CONF_DB.password, function(err, result) {
if (err) {
console.error('DB user authenticate fail: ' + err, err);
client.close();
console.log('Connect closed');
} else {
db.collection('tickTest', {}, function(err, collection) {
if (err) {
console.error('Access collection tickTest fail: ' + err, err);
client.close();
console.log('Connect closed');
} else {
collectionTickTest = collection;
// runTest();
// analysisSetInterval();
analysisSetTimeout();
}
})
}
})
} else {
console.error('Cannot access db gtip')
}
}
});
結果分析
一、1秒測試
tickTest analysis setInterval
count: 26875
sumDiff: 32638
average: 1001.2144372093023
max: 1174, min: 998, maxDiff: 176
variance: 4.110766477637712
tickTest analysis setTimeout
count: 26875
sumDiff: 32629
average: 1001.2141023255814
max: 1174, min: 999, maxDiff: 175
variance: 4.1382837776008845
- 在服務器上運行了7個半小時左右,總次數為26875 * 1秒
- 總延遲都將近半分鐘,有32秒多
- 平均值看起來挺接近1000的,但次數多了還是有影響,特別是需要跟時間同步的時候。
- 極差主要表現為延遲,最大的延遲達到174ms
- 方差則表示穩定程度,兩者都差不多
二、1分鐘測試
tickTest analysis setInterval
count: 241
sumDiff: -59229
average: 59754.236514522825
max: 60028, min: 59999, maxDiff: 29
variance: 61738.17462713403
tickTest analysis setInterval
count: 241
sumDiff: -59229
average: 59754.236514522825
max: 60028, min: 59999, maxDiff: 29
variance: 61738.17462713403
- 在服務器上運行了6個小時,60000 * 241
- 因為代碼是延遲一個Interval才寫入第一次,所以計算出來的值少了1分鐘
- 以分鐘級的形式進行調用穩定性比以秒級高,總延遲在1秒內,極差也可接受