我创建了代码来查看我的静态压缩方法执行的速度有多快,我注意到第一次执行需要8,500,000纳秒,第二次执行需要大约一半,然后在0纳秒之后执行。为什么呢?
private void CheckPerformance()
{
while (KeepRunning)
{
//generates a complex random 500 character string
string text = GenerateString(500, 4);
DateTime beginTime = DateTime.Now;
byte[] bytes = Compress(text); // < - timing this
long elapsedTicks = DateTime.Now.Ticks - beginTime.Ticks;
Console.WriteLine(" {0:N0} nanoseconds", elapsedTicks * 100);
//sleep for 5 seconds
Thread.Sleep(5000);
}
}
public static byte[] Compress(string text)
{
using (MemoryStream output = new MemoryStream())
{
using (DeflateStream ds = new DeflateStream(output, CompressionMode.Compress))
{
using (StreamWriter writer = new StreamWriter(ds, Encoding.UTF8))
{
writer.Write(text);
}
}
return output.ToArray();
}
}
答案 0 :(得分:1)
DateTime.Now
每秒更新大约10次,但不要引用我(可能取决于硬件和软件设置)。它也很慢,因为它需要弄清楚系统的时区。 UtcNow
速度更快,但仍会缓存一段时间。因此,它可能在后续调用中使用缓存版本。
使用StopWatch
代替更准确的测量。 StopWatch
通过利用硬件实现高精度。您可以使用Stopwatch.IsHighResolution
进行检查。
using System.Diagnostics;
Stopwatch sw = new Stopwatch();
sw.Start();
// code to benchmark
sw.Stop();
让我们看看你是否得到相同的指标。
修改强>
虽然您的方法确实需要进行JIT编译,但差异不能归因于JIT编译,因为它只会被JIT编译一次(并不总是,但在您的情况下它将是一次),然后重用。因此,只有第一次呼叫需要更长时间,后续呼叫应该相同。要抛弃这个假设,只需在基准测试阶段之外调用Compress
,以便进行JIT编译。然后对它进行基准测试,现在不会发生JIT编译,DateTime
仍然会给你随机结果,因为它是缓存的。
注意:JIT编译器不一定总是将整个方法编译成机器代码,但仅在执行通过代码时才编译。因此,如果您有if语句,则在通过块传递执行之前,可能无法编译块。但是你的if语句没有,所以这就是JIT编译一次的原因。
此外,我们无法自信地说这是由于JIT编译,因为Compress
方法可能是inlined,但在您的情况下很可能没有内联,因为您很可能已经调试器打开,因此,JIT优化将被禁用。
尝试使用此代码,即使执行相同的代码,您也会注意到它会为经过的时间提供随机结果:
for (int i = 0; i < 1000; i++)
{
DateTime beginTime = DateTime.UtcNow;
var sw = Stopwatch.StartNew();
while (sw.ElapsedTicks < 100)
{
Console.WriteLine("*");
}
long elapsedTicks = DateTime.UtcNow.Ticks - beginTime.Ticks;
Console.WriteLine(" {0:N0} nanoseconds", elapsedTicks * 100);
}
在我的系统上,如果我将此行更改为sw.ElapsedTicks < 2050
,则始终存在一致的非零报告差异。这意味着当DateTime.Now
获得新值而不是使用缓存值时。
总之,我不认为JIT编译是你注意到的解释。
答案 1 :(得分:1)
当你第一次碰到它时,它会被咬住。所以这需要时间。不确定为什么第二次和第三次不同。