patterncsharpMinor
Norms, rules or guidelines for calculating and showing ETA/ETC for a process
Viewed 0 times
etaguidelinesshowingprocesscalculatingforandrulesnormsetc
Problem
ETC = "Estimated Time of Completion"
I'm counting the time it takes to run through a loop and showing the user some numbers that tells him/her how much time, approximately, the full process will take. I feel like this is a common thing that everyone does on occasion and I would like to know if you have any guidelines that you follow.
Here's an example I'm using at the moment:
As I am a programmer at the very start of my career I'm curious to see what you would do in this situation. My main concern is the fact that I calculate and update the UI for every loop, is this bad practice?
Are there any do's/don't's when it comes to estimations like this? Are there any preferred ways of doing it, e.g. update every second, update every ten logs, ca
I'm counting the time it takes to run through a loop and showing the user some numbers that tells him/her how much time, approximately, the full process will take. I feel like this is a common thing that everyone does on occasion and I would like to know if you have any guidelines that you follow.
Here's an example I'm using at the moment:
int itemsLeft; //This holds the number of items to run through.
double timeLeft;
TimeSpan TsTimeLeft;
list avrage;
double milliseconds; //This holds the time each loop takes to complete, reset every loop.
//The background worker calls this event once for each item. The total number
//of items are in the hundreds for this particular application and every loop takes
//roughly one second.
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//An item has been completed!
itemsLeft--;
avrage.Add(milliseconds);
//Get an avgrage time per item and multiply it with items left.
timeLeft = avrage.Sum() / avrage.Count * itemsLeft;
TsTimeLeft = TimeSpan.FromSeconds(timeLeft);
this.Text = String.Format("ETC: {0}:{1:D2}:{2:D2} ({3:N2}s/file)",
TsTimeLeft.Hours,
TsTimeLeft.Minutes,
TsTimeLeft.Seconds,
avrage.Sum() / avrage.Count);
//Only using the last 20-30 logs in the calculation to prevent an unnecessarily long List<>.
if (avrage.Count > 30)
avrage.RemoveRange(0, 10);
milliseconds = 0;
}
//this.profiler.Interval = 10;
private void profiler_Tick(object sender, EventArgs e)
{
milliseconds += 0.01;
}As I am a programmer at the very start of my career I'm curious to see what you would do in this situation. My main concern is the fact that I calculate and update the UI for every loop, is this bad practice?
Are there any do's/don't's when it comes to estimations like this? Are there any preferred ways of doing it, e.g. update every second, update every ten logs, ca
Solution
Your approach looks reasonable if one makes the assumption that the average time for item processing is roughly the same for each item.
Updating the UI once a second is ok, updating it more often does not make much sense since the typically user cannot follow that visually either. If this really becomes a bottleneck, you might consider to add some code like
(you will have to introduce those two variables
Of course, when your progress event gets called more often (for example, several 10,000s a second), you will have to think about further optimizations, since even without the UI you will have to do some time value management or calculations. But as long as this is not the case, keep things simple.
This one here
looks like premature optimization, I guess
will give you a more smooth behaviour (and I guess you won't notice the difference in running time in most real-world cases).
Furthermore, for testing purposes, you may consider to refactor the average-time calculation into a
Updating the UI once a second is ok, updating it more often does not make much sense since the typically user cannot follow that visually either. If this really becomes a bottleneck, you might consider to add some code like
if(timeWhenUIWasUpdated < currentTime-1.0)
{
this.Text = String.Format(/*...*/);
timeWhenUIWasUpdated = currentTime; // unit: seconds
}(you will have to introduce those two variables
timeWhenUIWasUpdated and currentTime into your code).Of course, when your progress event gets called more often (for example, several 10,000s a second), you will have to think about further optimizations, since even without the UI you will have to do some time value management or calculations. But as long as this is not the case, keep things simple.
This one here
if (avrage.Count > 30)
avrage.RemoveRange(0, 10);looks like premature optimization, I guess
avrage.RemoveRange(0, 1);will give you a more smooth behaviour (and I guess you won't notice the difference in running time in most real-world cases).
Furthermore, for testing purposes, you may consider to refactor the average-time calculation into a
SlidingAverageCalculator class, separating the logic fully from the background worker and the UI display. This will make it really easy to write unit tests for that part of the code.Code Snippets
if(timeWhenUIWasUpdated < currentTime-1.0)
{
this.Text = String.Format(/*...*/);
timeWhenUIWasUpdated = currentTime; // unit: seconds
}if (avrage.Count > 30)
avrage.RemoveRange(0, 10);avrage.RemoveRange(0, 1);Context
StackExchange Code Review Q#26112, answer score: 2
Revisions (0)
No revisions yet.