2

我一直想知道所有具有进度条的程序如何几乎准确地知道完成操作(以及程序工作的整个处理)所需的时间,从而能够将其与进度条进行映射。

在 C# 中,我在处理进度条时总是会遇到困难。我得出的结论是,没有通用的解决方案,是吗?

我不是在问这个:

“例如:你怎么知道File.ReadAllBytes(path)读取一个文件需要多少时间?简单,在它之前启动一个秒表,然后停止并读取它之后的时间。但这只是在你的计算机上,在你的 CPU 上,在你的磁盘上!- 1MB的读数会和你的机器和其他的大多不同”

我在问我怎么知道一件事在进入它之前需要多长时间才能完成?我的意思是,我必须知道在执行之前需要多少时间File.ReadAllBytes(),以便进度条可以在方法执行期间相应地步进。

一种愚蠢的做法是做两次!开始运行,计算时间,然后再次运行,但这次你踩了进度条(lol)

我不知道复杂性是否与此有关。我在编写自己的方法和函数时使用 big-O,而不是在处理预定义函数时。

编辑:只是一个例子:我制作了一个异或文件并用异或形式覆盖它的程序。现在这涉及 1-将文件的字节读取到字节数组。对它们进行 2 异或运算。3-将它们再次写回文件。现在如果我想使用进度条,我怎样才能知道这些操作需要多少时间,以便我可以相应地增加进度条?

我对此的解决方案是使用一个全局变量(如 prgBar),将 XORing 分配给一个单独的线程,并且每次我从我从文件中读取的字节数组中异或一个字节时,在该线程中递增“prgBar”,然后在主线程中,我使用了一个计时器,我所做的每个滴答声:prgressBar.Value = prgBar 我遇到了这个问题,它甚至不准确,它可能开始晚了。

4

5 回答 5

2

您所描述的是停机问题。长话短说,您无法判断任意过程何时结束,但您可以进行猜测。

例如,假设您有 1MB 需要传输。如果一次传输一个字节,然后在每个字节之后更新进度条,那么它看起来会很流畅。还可以显示基于过去的时间估计。例如,如果我花了 1 秒来移动 1MB 的 10%,那么我应该在 9 秒内完成。

希望有帮助。

于 2012-12-11T22:03:54.773 回答
2

快速的回答是“他们没有”。你有没有见过在 20 秒内从“还剩 20 分钟”跳到“还剩 5 分钟”的进度条?还是那些说“还剩0:00”然后就坐在那里的人?


更好的答案是“他们估计”。我能想到的有两种形式,但我没有做任何广泛的研究。不过,他们都使用过去的表现来估计未来的进展。

第一种形式适用于一系列具有相似复杂性但任意长度的离散任务,例如文件复制/删除。您从一个较低的基本估计或“正在计算...”消息开始,然后在每个文件完成后,您根据复制/删除所有文件所需的时间重新估计需要多长时间,因此远的。例如,如果你要删除 2000 个文件,而前 5{400, 200, 900, 100, 400 ms}个文件在向您的用户显示“还剩 13 分钟”(798 秒)的进度条。它可能不准确,但如果你每隔几个文件就不断地修改它,它会进展得相当顺利。

第二种形式是任务的长度及其复杂性已知(并且变化很大),但速度仍然未知,例如使用安装程序。在这种情况下,您可以通过在测试中多次运行安装程序并弄清楚不同组件的时间之间的关系来做出估计。这可能像比较各个步骤以得出公式一样复杂,或者像仅将安装时间百分比分配给每个阶段一样简单。然后,当用户进行安装时,您知道前 2% 的组件需要 X 秒的持续时间,因此估计还剩 50*X 秒。这就是为什么安装人员似乎经常徘徊或跳来跳去的原因 - 他们正在等待比平时花费更长的时间,或者他们发现他们不需要在您的系统上执行步骤。


最后,这只是一个估计。百分比可能很难(“我在第 1/5 步,所以显示完成了 20%”),但持续时间永远不可能。有关这背后的理论,请参阅 Jbecwar 的回答。

于 2012-12-11T22:29:27.230 回答
1

您必须自己计算操作的完整性,并且并不总是可以准确地完成。要读取文件,您可以执行诸如获取行数,计算您已阅读的行数,然后执行当前/总计以显示进度之类的操作。对于更复杂的操作,这实际上效果更好。

假设您有一个包含 1000 个对象的数组,需要处理这些对象的数据。您在 for 循环中执行此操作,因此进度条可以简单地显示i/array.length. 该ReadAllBytes示例不好,因为无法获取该任务的进度。.NET 方法将返回所有字节,因此您只能知道任务何时开始和完成,更不用说任务会如此之快以至于不需要进度条。

于 2012-12-11T22:07:32.357 回答
1

实际上,您应该分批读取文件(例如,每次 20KB),这样您就可以在每批之后增加进度条

于 2012-12-12T03:09:17.347 回答
0

您是对的,除非您考虑将进度条用作“我仍在处理”栏,否则进度条没有万能的。可以让进度条一遍又一遍地从 0 更新到 100(最大值)。

有时您会知道自己的进展情况,并可以将其报告给用户。

让我们举个File.ReadAllBytes(path)例子:

您应该能够获得文件的大小。您还可以通过递增变量来确定到目前为止已读取的字节数。通过做一些简单的数学运算,您可以使用 bytesRead/bytesInFile 来获得完成的百分比。通过每 500 毫秒计时一次的计时器将此情况报告给用户,您应该会看到带有适当反馈的进度条。

于 2012-12-11T22:02:09.877 回答