Задать вопрос
@SergeySerge11

Почему одинаковые делегаты работают по разному, В 10 Раз разница в скорости?

Что за ерунда наблюдается.
В примере создаются 2 Одинаковых делегата(Ели ели нашел что в них дело, проверяя 1000 комбинаций причин), тот кто первый запустится будет в 10 раз быстрее. Почему так происходит, неожиданно поймал такое.
Вот для простоты пример, замеряю работу функции, создал расширение For для выполнения N раз функции для элементов массивов, без него эффект не наблюдается, если допустим цикл внутрь m(()=>{for....}); вставить.

Немного подебажил, и вроде заметил, что второй в порядке вызова метод вообще не инлайнится, и там прям стандартный метод вместо хотя бы 2 инструкций "lea lea eax, [rcx + rdx]; ret" там 10-20 как в debug режиме.

var  arr=Enumerable.Range(0,1_000_000).Select(i=> (X:(uint)i, Y:  1u)).ToArray(); // от n не зависит, (кортеж артефакт поиска причины )
        // одинаковые делегаты, второй в порядке вызывания будет до 10-100 раз медленнее!!!!
        var del =  () => arr.For ((a) => test1(a.Item1, a.Item2));
        var del2 =  () => arr.For ((a) => test1(a.Item1, a.Item2));
        m(del);    // зависит от порядка  вызова  
        m(del2);  

        // какая-то случ функция до 50 асемблерных строк всяких инструкций эффект наблюдается где-то
            static uint test1(uint i, uint j)
     {
         return i + j; 

     }
public static class ArrayExtensions{
       public static void For <T>(this T[] arr, Action<T> func)
       {

           int len = arr.Length; 
           foreach(var i  in arr)
           {
               func(i);
           }
       }
}
        public static void m(Action action, Action load = null)
        {
            Stopwatch sw = Stopwatch.StartNew();
            load?.Invoke();
            action();  
            load?.Invoke();
            
            sw.Start();
            action();
            sw.Stop();
            int n = (int)(5_000 / (sw.Elapsed.TotalMilliseconds + 0.001f));
            if (n == 0)
                n = 1;
            List<double> times = new List<double>();
            for (int i = 0; i < n; i++)
            {
                load?.Invoke();
                sw.Restart();
                action();
                sw.Stop();
                times.Add(sw.Elapsed.TotalMilliseconds);
            }

            double sum = times.Sum();
            double average = sum / n;
            double err = Math.Sqrt(times.Aggregate(0.0, (acc, e) => acc += (e - average) * (e - average)) / (n - 1));
            Console.WriteLine($"Test func: {action.Method.Name}");
            Console.WriteLine($"Count invoke: {n}");
            Console.WriteLine("Standard deviation: {0,20:f4} ms", err);
            Console.WriteLine("Max:                {0,20:f4} ms", times.Max());
            Console.WriteLine("Min:                {0,20:f4} ms", times.Min());
            var c1 = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Mean time         : {0,20:f4} ms", average);
            Console.ForegroundColor = c1;
            Console.WriteLine();

        }


Test func: b__1
Count invoke: 5803
Standard deviation: 0.0146 ms
Max: 0.3772 ms
Min: 0.0362 ms
Mean time : 0.0509 ms

Test func: b__1
Count invoke: 55555
Standard deviation: 0.0091 ms
Max: 0.4715 ms
Min: 0.0355 ms
Mean time : 0.0420 ms

Test func: b__2
Count invoke: 3902
Standard deviation: 0.0589 ms
Max: 0.9081 ms
Min: 0.3880 ms
Mean : 0.4358 ms

Test func: b__2
Count invoke: 6124
Standard deviation: 0.0519 ms
Max: 0.7931 ms
Min: 0.3880 ms
Mean : 0.4263 ms
  • Вопрос задан
  • 52 просмотра
Подписаться 1 Сложный 3 комментария
Помогут разобраться в теме Все курсы
  • OTUS
    C# Developer. Professional
    6 месяцев
    Далее
  • Ulearn.me
    Основы программирования на примере C#. Часть 1
    1 неделя
    Далее
  • Ulearn.me
    Основы программирования на примере C#. Часть 2
    1 неделя
    Далее
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы