I know - it's been too long since my last post and i feel ashamed. So here goes.
I have put together a neat progress timer class for such occasions when you have a long running process looping over a bunch of items and doing its thing. The timer keeps track of the recent times and remaining time. Enough of the chit-chat - to the code...
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; public class ProgressTimer { private readonly Queue_timeQueue; private int _itemsRemaining; private int _limit; private Stopwatch _stopWatch; public ProgressTimer(int historyLimit) { if(historyLimit <= 0) throw new ArgumentOutOfRangeException("historyLimit", "History limit must be greater than 0."); _timeQueue = new Queue (); _stopWatch = new Stopwatch(); _itemsRemaining = 0; _limit = historyLimit; } public void Initialize(int totalItems) { _itemsRemaining = totalItems; _timeQueue.Clear(); if(_stopWatch.IsRunning) _stopWatch.Stop(); _stopWatch.Reset(); } public void BeginStep() { ThrowIfStopWatchRunning(); _itemsRemaining--; _stopWatch.Reset(); _stopWatch.Start(); } public void EndStep() { _stopWatch.Stop(); if (_timeQueue.Count >= _limit) { _timeQueue.Dequeue(); } _timeQueue.Enqueue(TimeSpan.FromMilliseconds(_stopWatch.ElapsedMilliseconds)); } public TimeSpan StepTime { get { ThrowIfStopWatchRunning(); return TimeSpan.FromMilliseconds(_stopWatch.ElapsedMilliseconds); } } public TimeSpan RemainingTime { get { ThrowIfStopWatchRunning(); if (_itemsRemaining <= 0) return new TimeSpan(0); var averageTimeMilliseconds = _timeQueue.Average(x => x.TotalMilliseconds); var totalRemainingMilliseconds = _itemsRemaining * averageTimeMilliseconds; return TimeSpan.FromMilliseconds(totalRemainingMilliseconds); } } public int QueuedTimesCount { get { return _timeQueue.Count; } } public int ItemsRemaining { get { return _itemsRemaining; } } private void ThrowIfStopWatchRunning() { if (_stopWatch.IsRunning) throw new InvalidOperationException("The step is still in progress. End the step by calling EndStep()."); } }
And here's a sample of how to put it all to good use...
var timer = new ProgressTimer(2); timer.Initialize(2); timer.BeginStep(); // As if real work is happening Thread.Sleep(3000); timer.EndStep(); var stepTime = timer.StepTime; var remainingTime = timer.RemainingTime; timer.BeginStep(); // As if real work is happening Thread.Sleep(2000); timer.EndStep(); stepTime = timer.StepTime; remainingTime = timer.RemainingTime;
I hope someone out there benefits from this. And as always I'm open for comments to improve the above piece of code.
Peace,
Mihkel
Mihkel