setInterval能否随着时间漂移?

4

我有两个Node.js Web服务器。我在Web服务器内部缓存数据。我根据系统时间同步缓存加载/清除。我已经对所有主机进行了时间同步。

现在,我使用以下代码每15分钟清除一次缓存:

millisTillNexthour = "Calculate millis remaining until next hour"

setTimeout(function() {
  setInterval(function() {
    cache.clear();
  }, 60000*15);
}, millisTillNexthour);

我的期望是即使这个进程永远运行,缓存也将在每小时的第15分钟清除一次。

我的问题是:setInterval函数是否会随着时间漂移?

例如:现在它会在 10:00 10:15 10:30 10:45 11:00 ...... 清除缓存。

但是,可能会发生这种情况吗?当应该在10:15清除缓存时,setInterval函数在系统时间10:20执行?

我不确定这是怎么回事,希望您能给予解答。谢谢!


除非有其他阻止其执行的事情,否则它应该尽可能靠近 :15 执行,但不要过早执行。 - Ian
1
从理论上讲不会。setInterval 的设计正是为了解决使用 setTimeout 调用自身(并且会漂移)所带来的问题。然而,Ian 是正确的;如果某些东西在它应该运行回调时阻塞了它 5 分钟,它将一直等到阻塞解除才能运行。不要依赖此功能进行金融交易或核威慑。 - Dave
我找到了另一个类似的帖子:https://dev59.com/W3NA5IYBdhLWcg3wYMt- - GJain
6个回答

2

可能我来晚了,但这是我刚刚解决时间滑动问题的方法。我使用了递归调用setTimeout()函数,而不是使用setInterval()。

var interval = 5000;
var adjustedInterval = interval;
var expectedCycleTime = 0;

function runAtInterval(){
    // get timestamp at very start of function call
    var now = Date.now();

    // log with time to show interval
    console.log(new Date().toISOString().replace(/T/, ' ').replace(/Z/, '') + " runAtInterval()");

    // set next expectedCycleTime and adjustedInterval
    if (expectedCycleTime == 0){
        expectedCycleTime = now + interval;
    }
    else {
        adjustedInterval = interval - (now - expectedCycleTime);
        expectedCycleTime += interval;
    }

    // function calls itself after delay of adjustedInterval
    setTimeout(function () {
        runAtInterval();
    }, adjustedInterval);
}

在每次迭代中,该函数会检查实际执行时间与先前计算的预期时间之间的差异,然后从“interval”中减去这个差异以产生“adjustedInterval”。这个差异可能是正数或负数,并且结果表明实际执行时间往往在“真实”值+/- ~5ms左右波动。
无论如何,如果您有一个每分钟执行一次的任务,并且您连续运行它一整天,使用此函数,您可以期望在整个一天中,每个小时都会有60次迭代发生。您不会遇到那种偶尔只有59个结果的小时,因为最终整整一分钟已经过去了。

1

1

setInterval 明显在漂移(尽管我同意它不应该)。我正在运行一个间隔为30秒的Node.js服务器。每次tick时,会进行一些异步的web请求,从开始到结束大约需要1秒钟。在接下来的29秒内没有其他用户级别/应用程序处理。

然而,我注意到在30分钟的过程中,发生了100毫秒的漂移。当然,底层操作系统并不应该为漂移负责,这只能是Node.js设计或实现上的某个缺陷。


0

它绝对可以,因为Javascript的工作方式(请参见事件循环)。

Javascript事件循环在其他排队的事件完成后执行setInterval队列。这些事件需要一些时间,会影响您的setInterval函数的执行时间,并随着时间的推移逐渐偏离。


0
你可以使用 Date() 对象来设置特定的时间,然后向日期添加一定数量的毫秒。

这不会为他们已经拥有的功能提供额外的健壮性。 - Dave
除非它基于包含24小时内每15分钟时间表示的对象或数组,并且缓存在事件上被清除。只是在这里大声思考而已。 - Dimitri Vorontzov
基于这样的想法,某些东西可能会占用系统资源,但计算机时钟仍将继续运行。 - Dimitri Vorontzov
内部,setInterval 使用系统时钟。要明确的是,setInterval 永远不会漂移,但它可能需要等待才能触发(如果在它应该运行的时间被阻塞了)。这适用于您可能做的任何事情,除了接管内核职责和热等待之外,尽管在其他语言中线程更普遍(有较少的东西可以导致其阻塞),这不是一个问题。 - Dave
好的。你是对的。在这种情况下,如果该函数在 Web Worker 上运行会有帮助吗? - Dimitri Vorontzov
它应该使其达到其他语言的水平,但我认为WebWorkers限制了你实际可以做的事情,因此可能不切实际。Node.js可能具有内置的线程支持,例如用于提供请求与运行后台任务等。我不确定。 - Dave

-1

在理想的情况下,setInterval 不应该出现偏移。但是由于其他占用系统资源的因素,它可能会被延迟。如果您需要更精确的解决方案,请使用 clock() 函数来 "校准" 您的节点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接