JS定时器误差:setTimeout和setInterval
2017-04-20 本文已影响0人
Franchen
引言
项目需要每隔一段时间运行某个方法,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秒内,极差也可接受