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