C# 我的静态方法似乎在重用时执行得更快。为什么?它会被缓存吗?

C# 我的静态方法似乎在重用时执行得更快。为什么?它会被缓存吗?,c#,performance,time,compression,benchmarking,C#,Performance,Time,Compression,Benchmarking,我创建了代码来查看静态压缩方法的执行速度,我注意到第一次执行需要850万纳秒,第二次大约需要一半,之后的所有操作都以0纳秒的速度执行。为什么? private void CheckPerformance() { while (KeepRunning) { //generates a complex random 500 character string string text = GenerateString(500, 4);

我创建了代码来查看静态压缩方法的执行速度,我注意到第一次执行需要850万纳秒,第二次大约需要一半,之后的所有操作都以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();
    }
}
private void CheckPerformance()
{
同时(继续修剪)
{
//生成一个500个字符的复杂随机字符串
字符串文本=生成器字符串(500,4);
DateTime beginTime=DateTime.Now;
字节[]字节=压缩(文本);//<-计时
long elapsedTicks=DateTime.Now.Ticks-beginTime.Ticks;
Console.WriteLine(“{0:N0}纳秒”,elapsedTicks*100);
//睡5秒钟
睡眠(5000);
}
}
公共静态字节[]压缩(字符串文本)
{
使用(MemoryStream输出=新的MemoryStream())
{
使用(DeflateStream ds=新的DeflateStream(输出,CompressionMode.Compress))
{
使用(StreamWriter=newstreamwriter(ds,Encoding.UTF8))
{
作者:写(文本);
}
}
返回输出.ToArray();
}
}

日期时间。现在每秒更新10次左右,但不要引用我的话(可能取决于硬件和软件设置)。它的速度也很慢,因为它需要计算出系统所在的时区
UtcNow
速度更快,但仍会被缓存一段时间。因此,它可以在后续调用中使用缓存版本

使用秒表进行更精确的测量<代码>秒表利用硬件实现高精度。您可以使用
秒表.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
方法,但在您的情况下,它很可能不是内联的,因为您很可能打开了调试器,因此,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);
}
for(int i=0;i<1000;i++)
{
DateTime beginTime=DateTime.UtcNow;
var sw=Stopwatch.StartNew();
而(西南ElapsedTicks<100)
{
Console.WriteLine(“*”);
}
long elapsedTicks=DateTime.UtcNow.Ticks-beginTime.Ticks;
Console.WriteLine(“{0:N0}纳秒”,elapsedTicks*100);
}
在我的系统上,如果我将该行更改为
sw.ElapsedTicks<2050
,则始终存在非零的差异。这意味着当
DateTime.Now
获取一个新值而不是使用缓存的值时,就会出现这种情况


总之,我不认为JIT编译可以解释您所注意到的问题。

日期时间。现在,每秒更新10次左右,但不要引用我的话(可能取决于硬件和软件设置)。它的速度也很慢,因为它需要计算出系统所在的时区
UtcNow
速度更快,但仍会被缓存一段时间。因此,它可以在后续调用中使用缓存版本

使用秒表进行更精确的测量<代码>秒表利用硬件实现高精度。您可以使用
秒表.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
方法,但在您的情况下,它很可能不是内联的,因为您很可能打开了调试器,因此,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);
}
for(int i=0;i<1000;i++)
{
DateTime beginTime=DateTime.UtcNow;
var sw=Stopwatch.StartNew();
当(