Получение имени метода вызывающей стороны - атрибут Reflection и CallerInfo

Просто отметили производительность использования StackTrace а также CallerInfo Attributes,

Шокирующе я обнаружил, что с помощью StackTrace гораздо быстрее, хотя каждый, где я читал, что To get the caller method name, the preferred approach is CallerInfo attributes,

public class Program
    {
        public static void Main(string[] args)
        {
          Method1();  
        }

         static void Method1([CallerMemberName]string memberName = "")
         {
            double stackTraceTimings = 0;
            var sw = new Stopwatch();

            foreach(var item in Enumerable.Range(1,1000).ToList())
            {
               sw.Start();
               var callerName = new StackFrame(1).GetMethod().Name;
               sw.Stop();
               stackTraceTimings += sw.Elapsed.TotalMilliseconds;
            }

            Console.WriteLine("Elapsed Time for retrieving the caller name using StackFrame in 1000 iterations ={0}",stackTraceTimings/1000);

            stackTraceTimings = 0;
            foreach(var item in Enumerable.Range(1,1000).ToList())
            {
                sw.Start();
                var callerName = (memberName);
                sw.Stop();
                stackTraceTimings += sw.Elapsed.TotalMilliseconds;
            }

            Console.WriteLine("Elapsed Time for retrieving the caller name using callerInfo Attribute in 1000 iterations ={0}",stackTraceTimings/1000);
        }

ВЫХОД: Истекшее время для получения имени вызывающего абонента с помощью StackFrame за 1000 итераций =9.48074760000001

Истекшее время для получения имени вызывающего абонента с использованием атрибута callerInfo за 1000 итераций =21.7074064

Я что-то не так понял? С помощью CallerInfo атрибуты является предпочтительным подходом, верно?

Спасибо за ответ ниже для указания.

Я должен перезапускать таймер каждый раз в цикле.

Итак, кто победит? Как сказано в ответе ниже, CallerInfo, Потому что это функция времени компиляции и она быстрее.

Истекшее время для получения имени вызывающего абонента с использованием StackFrame за 1000 итераций =0,00762619999999992

Истекшее время для получения имени вызывающего абонента с использованием атрибута callerInfo за 1000 итераций =0.00639420000000002

Я использовал приведенный ниже код (пересмотренный) и получил вышеуказанные результаты.

 public class Program
    {
        public static void Main(string[] args)
        {
          Method1();  
        }

         static void Method1([CallerMemberName]string memberName = "")
         {
            double stackTraceTimings = 0;
            var sw = new Stopwatch();

            foreach(var item in Enumerable.Range(1,1000).ToList())
            {
               sw.Start();
               var callerName = new StackFrame(1).GetMethod().Name;
               sw.Stop();
               Console.Write(callerName);
               sw.Restart();
               stackTraceTimings += sw.Elapsed.TotalMilliseconds;
            }

            Console.WriteLine("Elapsed Time for retrieving the caller name using StackFrame in 1000 iterations ={0}",stackTraceTimings/1000);


            stackTraceTimings = 0;
            foreach(var item in Enumerable.Range(1,1000).ToList())
            {
                sw.Start();
                var callerName = (memberName);
                Console.Write(callerName);
                sw.Stop();
                sw.Restart();

                stackTraceTimings += sw.Elapsed.TotalMilliseconds;
            }

            Console.WriteLine("Elapsed Time for retrieving the caller name using callerInfo Attribute in 1000 iterations ={0}",stackTraceTimings/1000);
        }
    }

1 ответ

Решение

Вы должны сбросить таймер до второго цикла. sw.Start начинается Stopwatch из состояния это было после первого цикла, поэтому второй результат - фактически время для суммированных вместе решений StackTrace и на основе атрибутов.

CallerMethodName это функция типа компиляции, она определенно должна быть быстрее.

С фиксированной синхронизацией кода для CallerMethodName из ваших результатов есть:

21,7074064 - (9,48074760000001 * 2) = 2,7459111999999806

Это намного быстрее, не так ли?

вычитали первый раз дважды: один раз из-за отсутствия Reset позвоните и один раз для += вместо = ,

Обновить

Эти результаты кажутся слишком большими. Вы уверены, что используете Release build, работающий вне Visual Studio? Я думаю, что нет, потому что в противном случае вы получите одинаковые результаты для обоих: callerName никогда не используется и, вероятно, будет оптимизирован для no-op (по крайней мере, для второго случая).

Другие вопросы по тегам