The idea is that when creating a timer, a tolerance value is specified that states how much variability is allowed in the timer. The tolerance allows timers with similar values to "grow together" into one timer. Examine the following example:
Timer 1: Trigger every 1 minutes with tolerance of 10 seconds
Timer 2: Trigger every 50 seconds with tolerance of 10 seconds
Coalesced Timer: Trigger every 60 seconds
Now becomes time to describe an algorithm for implementing coalescable timers. The goal is to minimize the number of times a timer is triggered. When a new timer is created, examine the existing timers, if any of the existing coalesced timers satisfy the requirements, add the new timer to the existing ones. If no existing coalesced timer handles the requirements specified, then create a new coalesced timer. Below is an implementation in TypeScript, which compiles down to basic JavaScript:
// Module containing all logic for coalescable timers module Coalescable { // Variable holding all coalesced timers that are aggregating the individual timers var timers: CoalescedTimer[] = new CoalescedTimer[]; export function SetCoalescableTimeout(expression: any, msec: number, tolerance: number): void { // Search existing coalesced timers for timers that can accomodate this request for (var index: number = 0; index < timers.length; index++) { var coalescedTimer: CoalescedTimer = timers[index]; if (msec - tolerance < coalescedTimer.msec && msec + tolerance > coalescedTimer.msec) { coalescedTimer.Timers.push(expression); return; } } // Create a new coalesced timer since none can accomodate this request var coalescedTimer: CoalescedTimer = new CoalescedTimer(msec) coalescedTimer.Timers.push(expression); timers.push(coalescedTimer); } class CoalescedTimer { constructor(public msec: number) { setInterval(function () => { for (var index: number = 0; index < this.Timers.length; index++) { new Function(this.Timers[index])(); } }, msec); } public Timers: any[] = new any[]; } } Coalescable.SetCoalescableTimeout("alert('1')", 5000, 10); // Will create a new coalesced timer since none exist. Coalescable.SetCoalescableTimeout("alert('2')", 6000, 2000); // Will be coalesced into the existing timer to run every 5000ms.
Obviously this is a first implementation. Many improvements could be made, such as minimizing distance from threshold when more than one coalesced timer exists to service a new timer request. There are also a few other interesting scenarios. Say creating a new timer means that a new coalesced timer will be created. In this case, it may make sense to move an existing timer to this new coalesced timer to reduce the difference from the requested interval and the coalesced interval. Also, cancelling or clearing a timeout should be supported.
- A good abstract by Microsoft on coalescable timers: http://go.microsoft.com/fwlink/p/?linkid=246618
No comments:
Post a Comment