C# DateTime.DayOfWeek微观优化

C# DateTime.DayOfWeek微观优化,c#,performance,datetime,micro-optimization,dayofweek,C#,Performance,Datetime,Micro Optimization,Dayofweek,首先: 96,28 172923452,50884515 352004290,111919170 521851120,168153321 683972846,215554958 846791857,264187194 1042803747,328459950 Monday 90,26 43772675,17902739 84299562,37339935 119418847,47236771 166955278,72444714 207441663,89852249 223981096,106

首先:

96,28
172923452,50884515
352004290,111919170
521851120,168153321
683972846,215554958
846791857,264187194
1042803747,328459950
Monday
90,26
43772675,17902739
84299562,37339935
119418847,47236771
166955278,72444714
207441663,89852249
223981096,106062643
275440586,125110111
327353547,145689642
363908633,163442675
407152133,181642026
445141584,197571786
495590201,217373350
520907684,236609850
511052601,217571474
610024381,260208969
637676317,275558318
  • 我问这个问题只是为了好玩和渴望学习。我必须承认,我喜欢搞微观优化(尽管它们从未导致我的任何开发速度有任何显著提高)

  • 在我的任何应用程序中,
    DateTime.DayOfWeek
    方法并不代表瓶颈

  • 在其他任何国家,这都不太可能成为问题。如果有人认为此方法会影响其应用程序的性能, 他应该考虑一下,然后,他应该做一个分析

  • 使用ILSpy反编译
    DateTime
    类,我们将了解
    DateTime.DayOfWeek
    是如何实现的:

    public DayOfWeek DayOfWeek
    {
        [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        get
        {
            return (DayOfWeek)((this.InternalTicks / 864000000000L + 1L) % 7L);
        }
    }
    
    public long Ticks
    {
        [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
        get
        {
            return this.InternalTicks;
        }
    }
    
    此方法执行以下操作:

  • 与当前日期对应的节拍数除以一天中现有的节拍数

  • 我们在前面的结果上加1,以便7除的余数在数字0和6之间

  • 这是计算一周中哪一天的唯一方法吗

    是否可以重新实现此功能以使其运行更快?

    让我们做一些调整

  • (864000000000)
    的素因子分解:
  • DayOfWeek
    现在可以表示为:

    public DayOfWeek DayOfWeek
    {                   
        get
        {
            return (DayOfWeek)(((Ticks>>14) / 52734375 + 1L) % 7L);
        }
    }
    
    我们在模7中工作,
    52734375%7
    1。因此,上述代码等于:

    public static DayOfWeek dayOfWeekTurbo(this DateTime date)
    {
        return (DayOfWeek)(((date.Ticks >> 14) + 1) % 7);
    }
    
    直觉上,它是有效的。但让我们用代码来证明它

    如果我们用这些数据制作一个图表,它看起来是这样的:

    ╔══════════════════════╦════════════════════╦═════════════════════╦═════════════╗
    ║ Number of iterations ║ Standard DayOfWeek ║ Optimized DayOfWeek ║   Speedup   ║
    ╠══════════════════════╬════════════════════╬═════════════════════╬═════════════╣
    ║                    0 ║                 96 ║                  28 ║ 3.428571429 ║
    ║                  100 ║          172923452 ║            50884515 ║ 3.398351188 ║
    ║                  200 ║          352004290 ║           111919170 ║ 3.145165301 ║
    ║                  300 ║          521851120 ║           168153321 ║ 3.103424404 ║
    ║                  400 ║          683972846 ║           215554958 ║ 3.1730787   ║
    ║                  500 ║          846791857 ║           264187194 ║ 3.205272156 ║
    ║                  600 ║         1042803747 ║           328459950 ║ 3.174827698 ║
    ╚══════════════════════╩════════════════════╩═════════════════════╩═════════════╝
    

    快3倍

    注意:该代码是使用Visual Studio 2013的发布模式编译的,运行时除应用程序外,所有内容都已关闭。(当然包括VS)

    我在实验室进行了测试, 英特尔®核心™ i3-2350M处理器和Windows®7 Home Premium 64位

    编辑:

    如前所述,如果不在日期边界上,此方法可能会失败

    根据Jon Skeet对这个答案的评论


    dayOfWeekTurbo
    不在日期边界时可能会失败。例如 考虑<代码>新日期时间(2014, 3, 11,21, 39, 30)< /代码> -您的方法认为 今天是星期五,实际上是星期二。“我们在模中工作” 7“是错误的方向,基本上。。。通过删除额外的 除此之外,一周中的某一天在一天中发生变化

    我决定编辑它

    如果我们更改
    proof()
    方法

    public static void proof()
    {
        DateTime date = DateTime.MinValue;
        DateTime max_date = DateTime.MaxValue.AddSeconds(-1);
        while (date < max_date)
        {
            if (date.DayOfWeek != date.dayOfWeekTurbo2())
            {
                Console.WriteLine("{0}\t{1}", date.DayOfWeek, date.dayOfWeekTurbo2());
                Console.ReadLine();
            }
            date = date.AddSeconds(1);
        }
    }
    
    此外,我们还更改了方法
    getAllDates()

    还会更快吗?答案是肯定的

    输出:

    96,28
    172923452,50884515
    352004290,111919170
    521851120,168153321
    683972846,215554958
    846791857,264187194
    1042803747,328459950
    Monday
    
    90,26
    43772675,17902739
    84299562,37339935
    119418847,47236771
    166955278,72444714
    207441663,89852249
    223981096,106062643
    275440586,125110111
    327353547,145689642
    363908633,163442675
    407152133,181642026
    445141584,197571786
    495590201,217373350
    520907684,236609850
    511052601,217571474
    610024381,260208969
    637676317,275558318
    


    快2倍

    看看这个问题:。不同之处在于我已经回答了自己的问题question@AdamSears我找到了。它在我的书签栏上:)
    dayOfWeekTurbo
    如果不在日期边界上,它可能会失败。例如,考虑<代码>新的DATETIME(2014, 3, 11,21, 39, 30)< /C> >您的方法认为实际是星期二的星期五。“我们在模7中工作”是错误的,基本上。。。通过去掉那个额外的除法,一周中的一天在白天发生变化。双向飞碟是绝对正确的。原始的
    long
    division
    InternalTicks/TimeSpan.TicksPerDay
    具有一个重要特性,即它截断了值中的时间部分。您的子表达式
    date.Ticks>>14
    每隔
    2**14==16384
    tick“递增”,因此您将在每过1.6384毫秒时获得一周中的新一天?
    public static DayOfWeek dayOfWeekTurbo2(this DateTime date)
    {
        return (DayOfWeek)((((date.Ticks >> 14) / 52734375L )+ 1) % 7);
    }
    
    public static IEnumerable<DateTime> getAllDates()
    {
        DateTime d = DateTime.MinValue;
        DateTime max = DateTime.MaxValue.AddHours(-1);
        while (d < max)
        {
            yield return d;
            d = d.AddHours(1);
        }
    }
    
    public static void benchDayOfWeek()
    {
    
        DateTime[] dates = getAllDates().ToArray();
        DayOfWeek[] foo = new DayOfWeek[dates.Length];
        for (int max_loop = 0; max_loop < 10000; max_loop ++)
        {
    
    
            Stopwatch st1, st2;
            st1 = Stopwatch.StartNew();
            for (int i = 0; i < max_loop; i++)
                for (int j = 0; j < dates.Length; j++)
                    foo[j] = dates[j].DayOfWeek;
            st1.Stop();
    
            st2 = Stopwatch.StartNew();
            for (int i = 0; i < max_loop; i++)
                for (int j = 0; j < dates.Length; j++)
                    foo[j] = dates[j].dayOfWeekTurbo2();
            st2.Stop();
    
            Console.WriteLine("{0},{1}", st1.ElapsedTicks, st2.ElapsedTicks);
    
        }
        Console.ReadLine();
        Console.WriteLine(foo[0]);
    
    }
    
    90,26
    43772675,17902739
    84299562,37339935
    119418847,47236771
    166955278,72444714
    207441663,89852249
    223981096,106062643
    275440586,125110111
    327353547,145689642
    363908633,163442675
    407152133,181642026
    445141584,197571786
    495590201,217373350
    520907684,236609850
    511052601,217571474
    610024381,260208969
    637676317,275558318
    
    ╔══════════════════════╦════════════════════╦════════════════════════╦═════════════╗
    ║ Number of iterations ║ Standard DayOfWeek ║ Optimized DayOfWeek(2) ║  Speedup    ║
    ╠══════════════════════╬════════════════════╬════════════════════════╬═════════════╣
    ║                    1 ║           43772675 ║               17902739 ║ 2.445026708 ║
    ║                    2 ║           84299562 ║               37339935 ║ 2.257624766 ║
    ║                    3 ║          119418847 ║               47236771 ║ 2.528090817 ║
    ║                    4 ║          166955278 ║               72444714 ║ 2.304588821 ║
    ║                    5 ║          207441663 ║               89852249 ║ 2.308697504 ║
    ║                    6 ║          223981096 ║              106062643 ║ 2.111781205 ║
    ║                    7 ║          275440586 ║              125110111 ║ 2.201585338 ║
    ║                    8 ║          327353547 ║              145689642 ║ 2.246923958 ║
    ║                    9 ║          363908633 ║              163442675 ║ 2.226521519 ║
    ║                   10 ║          407152133 ║              181642026 ║ 2.241508433 ║
    ║                   11 ║          445141584 ║              197571786 ║ 2.25306251  ║
    ║                   12 ║          495590201 ║              217373350 ║ 2.279903222 ║
    ║                   13 ║          520907684 ║              236609850 ║ 2.201546909 ║
    ║                   14 ║          511052601 ║              217571474 ║ 2.348895246 ║
    ║                   15 ║          610024381 ║              260208969 ║ 2.344363391 ║
    ║                   16 ║          637676317 ║              275558318 ║ 2.314124725 ║
    ╚══════════════════════╩════════════════════╩════════════════════════╩═════════════╝