什么是确定完成某些事情的剩余时间的好算法?我知道有多少总行数,已经完成了多少行,我该如何估算剩余时间?
为什么不?
(linesProcessed / TimeTaken)
(timetaken / linesProcessed) * LinesLeft = TimeLeft
TimeLeft
然后将以任何时间单位表达timeTaken
.
感谢你的评论,你应该这样:
(TimeTaken / linesProcessed) * linesLeft = timeLeft
所以我们有
(10 / 100) * 200
= 20秒现在10秒过去
(20 / 100) * 200
= 40秒现在剩下10秒钟我们处理100多行
(30 / 200) * 100
= 15秒现在我们都看到为什么复制文件对话框从3小时跳到30分钟:-)
我很惊讶没有人用代码回答这个问题!
正如@JoshBerke所回答的那样,计算时间的简单方法可以编码如下:
DateTime startTime = DateTime.Now; for (int index = 0, count = lines.Count; index < count; index++) { // Do the processing ... // Calculate the time remaining: TimeSpan timeRemaining = TimeSpan.FromTicks(DateTime.Now.Subtract(startTime).Ticks * (count - (index+1)) / (index+1)); // Display the progress to the user ... }
这个简单的例子非常适合简单的进度计算.
但是,对于更复杂的任务,有许多方法可以改进这种计算!
例如,当您下载大文件时,下载速度可能很容易波动.要计算最准确的"ETA",一个好的算法就是只考虑过去10秒的进度.查看ETACalculator.cs以获取此算法的实现!
ETACalculator.cs来自Progression--我写的一个开源库.它为各种"进度计算"定义了一个非常易于使用的结构.它可以轻松实现报告不同类型进度的嵌套步骤.如果您担心感知性能(如@JoshBerke所建议的那样),它将对您有所帮助.
确保管理感知的表现.
虽然所有进度条在测试中花费了相同的时间,但是两个特征使用户认为该过程更快,即使它不是:
进度条顺利完成
进度棒加速到最后
不要复活一个死的问题,但我一直回来参考这个页面.
您可以在Stopwatch类上创建一个扩展方法,以获得可获得估计剩余时间跨度的功能.
static class StopWatchUtils { ////// Gets estimated time on compleation. /// /// /// /// ///public static TimeSpan GetEta(this Stopwatch sw, int counter, int counterGoal) { /* this is based off of: * (TimeTaken / linesProcessed) * linesLeft=timeLeft * so we have * (10/100) * 200 = 20 Seconds now 10 seconds go past * (20/100) * 200 = 40 Seconds left now 10 more seconds and we process 100 more lines * (30/200) * 100 = 15 Seconds and now we all see why the copy file dialog jumps from 3 hours to 30 minutes :-) * * pulled from http://stackoverflow.com/questions/473355/calculate-time-remaining/473369#473369 */ if (counter == 0) return TimeSpan.Zero; float elapsedMin = ((float)sw.ElapsedMilliseconds / 1000) / 60; float minLeft = (elapsedMin / counter) * (counterGoal - counter); //see comment a TimeSpan ret = TimeSpan.FromMinutes(minLeft); return ret; } }
例:
int y = 500; Stopwatch sw = new Stopwatch(); sw.Start(); for(int x = 0 ; x < y ; x++ ) { //do something Console.WriteLine("{0} time remaining",sw.GetEta(x,y).ToString()); }
希望它会对某些人有用.
编辑:应该注意,当每个循环花费相同的时间时,这是最准确的.
编辑2:我创建了一个扩展方法,而不是子类化.