Извиквания на метод за сравнителен анализ в C#

Търся начин за сравнителен анализ на извикванията на метод в C#.

Кодирах структура от данни за университетско задание и току-що измислих начин да оптимизирам малко, но по начин, който би добавил малко режийни разходи във всички ситуации, докато превръщам O(n) повикване в O(1) в някои.

Сега искам да пусна и двете версии спрямо тестовите данни, за да видя дали си струва да внедря оптимизацията. Знам, че в Ruby можете да опаковате кода в блок Benchmark и той да изведе времето, необходимо за изпълнение на блока в конзолата - има ли нещо подобно за C#?


person Toms Mikoss    schedule 25.10.2009    source източник


Отговори (6)


Можете да използвате вградения клас Хронометър, за да „Осигурява набор от методи и свойства, които можете да използвате за точно измерване на изминалото време." ако търсите ръчен начин да го направите. Не съм сигурен обаче за автоматизирания.

person mike    schedule 25.10.2009
comment
хронометърът не е най-добрият начин за бенчмарк. Той използва регистрите на процесора, така че вашият собствен код не може да го използва. Можете да сравните кода с Хронометър и без него и разликата е до 3 пъти - person Evgeniy; 15.12.2015

Откраднато (и модифицирано) от отговора на Юрий:

private static void Benchmark(Action act, int iterations)
{
    GC.Collect();
    act.Invoke(); // run once outside of loop to avoid initialization costs
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < iterations; i++)
    {
        act.Invoke();
    }
    sw.Stop();
    Console.WriteLine((sw.ElapsedMilliseconds / iterations).ToString());
}

Често конкретен метод трябва да инициализира някои неща и не винаги искате да включите тези разходи за инициализация в общия си бенчмарк. Също така искате да разделите общото време за изпълнение на броя итерации, така че вашата оценка да е повече или по-малко независима от броя на итерациите.

person MusiGenesis    schedule 25.10.2009
comment
Чудесно, просто търсех бърз метод за сравнение на C#. - person Yuriy Faktorovich; 07.03.2013
comment
И сте намерили отговор, извлечен от един от вашите собствени отговори? StackOverflow съществува достатъчно дълго, след като това ми се случи няколко пъти: past me отговаря на въпрос, който задавам current me. - person MusiGenesis; 07.03.2013
comment
Пример: Benchmark(() => { /* your code */ }, 100); - person 2Toad; 22.12.2015

Откраднах повечето от следното от метода на Jon Skeet за сравнителен анализ:

private static void Benchmark(Action act, int interval)
{
    GC.Collect();
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < interval; i++)
    {
        act.Invoke();
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}
person Yuriy Faktorovich    schedule 25.10.2009
comment
Добавянето на локален GC.Collect() може да ви накара да пропуснете проблеми с глобалното разпределение на паметта, които влияят на производителността, но това прави локалните измервания по-точни. - person Danny Varod; 26.10.2009

Ето някои неща, които открих чрез опити и грешки.

  1. Изхвърлете първата партида от (хиляди) повторения. Те най-вероятно ще бъдат засегнати от JITter.
  2. Изпълнението на бенчмарк на отделен Thread обект може да даде по-добри и по-стабилни резултати. Не знам защо.
  3. Виждал съм някои хора да използват Thread.Sleep по някаква причина, преди да изпълнят бенчмарка. Това само ще влоши нещата. Не знам защо. Вероятно поради JITter.
  4. Никога не стартирайте бенчмарка с разрешено отстраняване на грешки. Кодът най-вероятно ще работи с порядъци по-бавно.
  5. Компилирайте приложението си с активирани всички оптимизации. Някои кодове могат да бъдат драстично повлияни от оптимизацията, докато други кодове няма да бъдат, така че компилирането без оптимизация ще повлияе на надеждността на вашия бенчмарк.
  6. Когато компилирате с активирани оптимизации, понякога е необходимо по някакъв начин да оцените резултата от бенчмарка (напр. да отпечатате стойност и т.н.). В противен случай компилаторът може да „разбере“ някои изчисления за безполезни и просто няма да ги извърши.
  7. Извикването на делегати може да има забележими допълнителни разходи при извършване на определени бенчмаркове. По-добре е да поставите повече от една итерация вътре в делегата, така че режийните разходи да имат малък ефект върху резултата от бенчмарка.
  8. Профайлърите могат да имат свои собствени допълнителни разходи. Те са добри в това да ви кажат кои части от вашия код са тесни места, но не са добри в реалното сравняване на две различни неща надеждно.
  9. Като цяло, фантастичните решения за сравнителен анализ могат да имат забележими разходи. Например, ако искате да сравните много обекти, използвайки един интерфейс, може да е изкушаващо да обвиете всеки обект в клас. Не забравяйте обаче, че конструкторът на класа също има допълнителни разходи, които трябва да бъдат взети под внимание. По-добре е всичко да е възможно най-просто и директно.
person GregRos    schedule 12.03.2013

Звучи сякаш искате профилиращ профил. Аз лично бих препоръчал EQATEC Profiler, тъй като той е най-добрият безплатен, който съм пробвал. Хубавото на този метод в сравнение с обикновения хронометър е, че той също предоставя разбивка на производителността на определени методи/блокове.

person Noldorin    schedule 25.10.2009

Профайлърите дават най-добрите показатели, тъй като те диагностицират целия ви код, но го забавят много. Профайлърите се използват за намиране на тесни места.

За оптимизиране на алгоритъм, когато знаете къде са тесните места, използвайте речник на име-->хронометър, за да следите критичните за производителността секции по време на изпълнение.

person Danny Varod    schedule 25.10.2009