3

我想以以下格式输出进程的剩余时间:

d hh:mm:ss

当进程开始时,它设置一个DateTime startTime具有当前时间的变量。

从那里我的 GUI 上有一个计时器,它每秒更新一个标签,这是我必须计算的剩余时间:

TimeSpan timeRemaining = TimeSpan.FromTicks(DateTime.Now.Subtract(startTime).Ticks * (iProgress.Maximum - iProgress.Value) / iProgress.Value);

并在标签上使用:

labelTimeRemaining.Text = timeRemaining.ToString(@"d\ hh\:mm\:ss");

然而,显示的时间变化会非​​常奇怪地跳跃几分钟并进入稳定模式。

我知道它应该一开始就跳,但它应该在某个时候稳定下来,对吗?

我每秒处理大约 1~3 条记录,但是每次更新剩余的时间会增加 10~20 分钟。

我做错了什么或者我该如何解决这个问题?

如果您需要更多信息或代码,请告诉我。

更新

以下是我正在使用的部分代码:

private Stopwatch _timer = new Stopwatch();
private int _total = 0;
private int _current = 0;

使用以下命令启动线程或任务:

private void MyTask()
{
    _timer.Reset();
    _timer.Start();
    for (int i = 0; i < _total; i++)
    {
        _current++;
        Thread.Sleep(500);
    }
    _timer.Stop();
}

使用以下函数创建一个 winforms Timer 以每秒运行一次:

if (_timer.IsRunning && _current > 0)
{
    float elapsedMin = ((float)_timer.ElapsedMilliseconds / 1000) / 60;
    float minLeft = (elapsedMin / _current) * (_total - _current);
    TimeSpan eta = TimeSpan.FromMinutes(minLeft);
    iStatus.Text = eta.ToString(@"d\ hh\:mm\:ss");
}
4

1 回答 1

2

根据您提供的评论,当您处理 10K 到 10M 条记录时,您可以看到波动相当大。这是将向您展示波动的测试示例。

DateTime dt = DateTime.Now;
Thread.Sleep(3000);
TimeSpan ts = TimeSpan.FromTicks(DateTime.Now.Subtract(dt).Ticks * (100000 - 7) / 7);
Debug.WriteLine(ts.ToString());
Thread.Sleep(1000);
ts = TimeSpan.FromTicks(DateTime.Now.Subtract(dt).Ticks * (100000 - 9) / 9);
Debug.WriteLine(ts.ToString());

此外,即使您处理整数除法

DateTime dt = DateTime.Now;
Thread.Sleep(3000);
TimeSpan ts = TimeSpan.FromTicks((long)((double)DateTime.Now.Subtract(dt).Ticks * (100000.0 - 7.0) / 7.0));
Debug.WriteLine(ts.ToString());

Thread.Sleep(1000);
ts = TimeSpan.FromTicks((long)((double)DateTime.Now.Subtract(dt).Ticks * (100000.0 - 9.0) / 9.0));
Debug.WriteLine(ts.ToString());

But if you could normalize your records number to percents. Let's say you have 100K records, 1K is one percent and that is done in approximately 1000/2/60 around 8 minutes. After 32 minutes you will have 4% done. After another you will have 6% done and after another 24 minutes you will have around 9% done but lets say 10%. After more 30 minutes you should have 14% done. And now, if you update your textBox rarely the users will have the illusion that you really know how long it will take, and you will end up changing time for hour or two, but do it on every minute or on every percent changed (have you ever copied 30GB on Windows?)

DateTime dt1 = DateTime.Now;
DateTime dt2 = DateTime.Now;
dt2 = dt2.AddMinutes(32);
ts = TimeSpan.FromTicks(dt2.Subtract(dt1).Ticks * (100 - 4) / 4);
Debug.WriteLine(ts.ToString());

dt2 = dt2.AddMinutes(16);
ts = TimeSpan.FromTicks(dt2.Subtract(dt1).Ticks * (100 - 6) / 6);
Debug.WriteLine(ts.ToString());

dt2 = dt2.AddMinutes(24);
ts = TimeSpan.FromTicks(dt2.Subtract(dt1).Ticks * (100 - 10) / 10);
Debug.WriteLine(ts.ToString());

dt2 = dt2.AddMinutes(30);
ts = TimeSpan.FromTicks(dt2.Subtract(dt1).Ticks * (100 - 14) / 14);
Debug.WriteLine(ts.ToString());
于 2012-10-24T00:29:01.803 回答