Получение имени метода вызывающей стороны - атрибут 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 (по крайней мере, для второго случая).