代码之家  ›  专栏  ›  技术社区  ›  Michael Buen

基准测试时如何使缓存失效?

  •  1
  • Michael Buen  · 技术社区  · 14 年前

    我有这段代码,当交换usingas和usingcast的顺序时,它们的性能也会交换。

    using System;
    using System.Diagnostics;
    using System.Linq;
    
    using System.IO;
    
    class Test
    {
        const int Size = 30000000;
    
        static void Main()
        {
            object[] values = new MemoryStream[Size];
    
    
    
            UsingAs(values);
            UsingCast(values);
    
    
            Console.ReadLine();
        }
    
        static void UsingCast(object[] values)
        {
            Stopwatch sw = Stopwatch.StartNew();
            int sum = 0;
            foreach (object o in values)
            {
                if (o is MemoryStream)
                {
                    var m = (MemoryStream)o;
                    sum += (int)m.Length;
                }
            }
            sw.Stop();
            Console.WriteLine("Cast: {0} : {1}", sum,
                              (long)sw.ElapsedMilliseconds);
        }
    
        static void UsingAs(object[] values)
        {
            Stopwatch sw = Stopwatch.StartNew();
            int sum = 0;
            foreach (object o in values)
            {
    
                if (o is MemoryStream)
                {
                    var m = o as MemoryStream;
                    sum += (int)m.Length;
                }
            }
            sw.Stop();
            Console.WriteLine("As: {0} : {1}", sum,
                              (long)sw.ElapsedMilliseconds);
        }
    
    
    }
    

    输出:

    As: 0 : 322
    Cast: 0 : 281
    

    做这个的时候…

    UsingCast(values);
    UsingAs(values);
    

    …结果如下:

    Cast: 0 : 322
    As: 0 : 281
    

    当你这样做的时候…

    UsingAs(values);
    

    …结果如下:

    As: 0 : 322
    

    当你这样做的时候:

    UsingCast(values);
    

    …结果如下:

    Cast: 0 : 322
    

    除了独立运行它们之外,如何 使无效 缓存,所以被基准测试的第二个代码不会接收第一个代码的缓存内存?

    撇开基准测试不谈,我很喜欢现代处理器实现这种缓存魔力的事实:-)

    [编辑]

    正如建议尝试这个更快的代码(假设)……

    static void UsingAsAndNullTest(object[] values)
    {        
        Stopwatch sw = Stopwatch.StartNew();
        int sum = 0;
        foreach (object o in values)
        {
            var m = o as MemoryStream;
            if (m != null)
            {                
                sum += (int)m.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("As and null test: {0} : {1}", sum,
                          (long)sw.ElapsedMilliseconds);
    }
    

    ……结果是:

    As and null test: 0 : 342
    

    比上面两个代码慢

    [编辑]:

    按照建议,每一个程序都要有自己的副本…

    static void UsingAs(object[] values)
    {
        object[] a = values.ToArray();
    
        Stopwatch sw = Stopwatch.StartNew();
        int sum = 0;
        foreach (object o in a)
        {
    
            if (o is MemoryStream)
            {
                var m = o as MemoryStream;
                sum += (int)m.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("As: {0} : {1}", sum,
                          (long)sw.ElapsedMilliseconds);
    }
    
    static void UsingCast(object[] values)
    {
        object[] a = values.ToArray();
    
        Stopwatch sw = Stopwatch.StartNew();
        int sum = 0;
        foreach (object o in a)
        {
            if (o is MemoryStream)
            {
                var m = (MemoryStream)o;
                sum += (int)m.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("Cast: {0} : {1}", sum,
                          (long)sw.ElapsedMilliseconds);
    }
    

    …输出:

    Cast: 0 : 282
    As: 0 : 282
    

    现在他们有同样的结果了,谢谢雷姆斯!

    运行cast和独立运行时,它们也会产生相同的结果(即282)。现在,至于他们为什么 更快 (从322毫秒到282毫秒)当他们拿到自己的数组副本时,我无法从中得到任何东西:-)那完全是另一回事

    1 回复  |  直到 11 年前
        1
  •  1
  •   Remus Rusanu    14 年前

    如果你想去掉图片中的二级缓存和TLB未命中,那么只需在相同大小的不同内存流上调用第二个测试。

    推荐文章