Skip to content

Instantly share code, notes, and snippets.

@Brian1KB
Created April 16, 2017 00:28
Show Gist options
  • Save Brian1KB/7006dfb938cf5ae8451f3bb0224d9cea to your computer and use it in GitHub Desktop.
Save Brian1KB/7006dfb938cf5ae8451f3bb0224d9cea to your computer and use it in GitHub Desktop.
High Precision Timer V1
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using log4net;
namespace MiNET.Utils
{
public class HighPrecisionTimer : IDisposable
{
private static readonly ILog Log = LogManager.GetLogger(typeof (HighPrecisionTimer));
private static readonly DedicatedThreadPool ThreadPool =
new DedicatedThreadPool(new DedicatedThreadPoolSettings(Environment.ProcessorCount));
private static readonly List<HighPrecisionTimer> Timers = new List<HighPrecisionTimer>();
private static readonly Stopwatch Stopwatch = new Stopwatch();
private static readonly object TimersLock = new object();
private static bool _shouldClose;
private readonly Action<object> _action;
private readonly int _interval;
private long _nextStop;
private long _queueTime;
static HighPrecisionTimer()
{
Stopwatch.Start();
var thread = new Thread(() =>
{
Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
Thread.CurrentThread.Name = "High Precision Timer Ticker";
var completedTickTime = Stopwatch.ElapsedMilliseconds;
while (!_shouldClose)
{
var timeSinceLastTick = Stopwatch.ElapsedMilliseconds - completedTickTime;
if (timeSinceLastTick > 15) Log.Warn($"{timeSinceLastTick}ms since last tick!");
HighPrecisionTimer[] timers;
lock (TimersLock)
{
timers = Timers.ToArray();
}
foreach (var timer in timers)
{
if (Stopwatch.ElapsedMilliseconds < timer._nextStop) continue;
timer._nextStop = Stopwatch.ElapsedMilliseconds + 1000*60;
timer._queueTime = Stopwatch.ElapsedMilliseconds;
var stopwatch = new Stopwatch();
stopwatch.Start();
ThreadPool.QueueUserWorkItem(() =>
{
var queueTime = Stopwatch.ElapsedMilliseconds - timer._queueTime;
if (queueTime > 10) Log.Warn($"Queue took {queueTime}ms to execute action!");
try
{
timer._action.Invoke(timer);
}
catch (Exception e)
{
Log.Error("Exception while processing precision action: ", e);
}
finally
{
timer._nextStop = Stopwatch.ElapsedMilliseconds + timer._interval;
}
});
stopwatch.Stop();
if (stopwatch.ElapsedMilliseconds > 5)
Log.Warn($"Took {stopwatch.ElapsedMilliseconds}ms to add action to queue!");
}
completedTickTime = Stopwatch.ElapsedMilliseconds;
Thread.Yield();
}
});
thread.Start();
}
public HighPrecisionTimer(int interval, Action<object> action)
{
_action = action;
_interval = interval;
_nextStop = Stopwatch.ElapsedMilliseconds + interval;
lock (TimersLock)
{
Timers.Add(this);
}
}
public void Dispose()
{
lock (TimersLock)
{
Timers.Remove(this);
}
}
public static void Close()
{
_shouldClose = true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment