我想获得我必须执行一个循环的最大计数,它需要 x 毫秒才能完成。
例如。
int GetIterationsForExecutionTime(int ms)
{
int count = 0;
/* pseudocode
do
some code here
count++;
until executionTime > ms
*/
return count;
}
我如何完成这样的事情?
最佳答案
I want to get the maximum count I have to execute a loop for it to take x milliseconds to finish.
首先,不要那样做。如果需要等待一定的毫秒数 不要在循环中忙等待 .相反,启动一个计时器并返回。当计时器滴答作响时,让它调用一个方法,从您离开的地方恢复。
Task.Delay
方法可能是一个很好的使用方法;它会为您处理计时器的详细信息。如果您的问题实际上是关于如何计算某些代码所花费的时间,那么您需要的不仅仅是一个好的计时器。有很多艺术和科学来获得准确的时间。
首先,您应该始终使用
Stopwatch
并且永远不要使用 DateTime.Now
对于这些时间。秒表旨在成为一个高精度计时器,用于告诉您经过了多少时间。 DateTime.Now
是一个低精度计时器,用于告诉您是否该看神秘博士了。你不会用挂钟来为奥运会计时;你会使用你能拿到的最高精度的秒表。因此,请使用为您提供的那个。其次,您需要记住 C# 代码是及时编译的。由于分析循环调用的代码的抖动成本,因此第一次执行循环的成本可能比后续每次都要高出数百或数千倍。如果您打算测量循环的“热”成本,那么您需要在开始计时之前运行一次循环。如果您打算测量包括 jit 时间在内的平均成本,那么您需要决定多少次构成合理的试验次数,以便平均计算正确。
第三,您需要确保运行时没有佩戴任何铅块。切勿在调试时进行性能测量。这样做的人数之多令人吃惊。如果您在调试器中,那么运行时可能会与调试器来回交谈,以确保您获得所需的调试体验,而这种交谈需要时间。抖动生成的代码比平时更糟糕,因此您的调试体验更加一致。垃圾收集器收集不那么积极。等等。始终在调试器之外运行性能测量,并打开优化。
第四,请记住,虚拟内存系统会产生与抖动类似的成本。如果您已经在运行托管程序,或者最近运行了一个托管程序,那么您需要的 CLR 页面可能是“热的”——已经在 RAM 中——它们在那里速度很快。如果不是,那么这些页面可能在磁盘上很冷,并且需要进行页面错误处理。这会极大地改变时间。
第五,请记住抖动可以进行您意想不到的优化。如果您尝试计时:
// Let's time addition!
for (int i = 0; i < 1000000; ++i) { int j = i + 1; }
抖动完全在其删除整个循环的权利范围内。它可以意识到循环不计算程序中其他任何地方使用的值,并将其完全删除,使其时间为零。它这样做吗?也许。也许不吧。这取决于抖动。您应该测量实际代码的性能,其中计算出的值实际上是以某种方式使用的;然后抖动就会知道它不能优化它们。
第六,垃圾收集器可以丢弃产生大量垃圾的测试时间。假设你有两个测试,一个会产生很多垃圾,一个会产生一点点。如果幸运地第一个测试设法在没有收集的情况下运行但第二个测试触发了一个,则收集第一个测试产生的垃圾的成本可以“收费”到运行第二个测试所花费的时间。如果您的测试产生大量垃圾,那么请考虑 (1) 我的测试开始时是否现实?对不切实际的程序进行性能测量没有任何意义,因为您无法对真实程序的行为做出正确的推断。并且(2)我应该向产生垃圾的测试收取垃圾收集的费用吗?如果是这样,那么请确保在测试时间完成之前强制进行完整收集。
第七,您正在多线程、多处理器环境中运行您的代码,在该环境中线程可以随意切换,并且线程量(操作系统将给另一个线程的时间量,直到您的线程有机会再次运行)大约是16 毫秒。 16 毫秒大约是 5000 万个处理器周期。如果线程切换发生在您尝试测量的数百万个处理器周期之一内,则获得亚毫秒操作的准确计时可能会非常困难。考虑到这一点。
关于c# - 以毫秒为单位测量 .net 中的代码速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10111159/