Вы можете объявить к вашему методу испытаний делегата и использовать один из следующих методов расширения для выполнить его N раз. На основе переданной строки формата вы получаете выводимого на консоль:
- Первый вызов времени
- Прошедшее время
- частота вызовов
которые все полезные значения. В методах расширения используется секундомер, чтобы получить максимальную точность.
Action acc = hideDataUsingAlgorithm;
acc.Profile(100*1000, "Method did run {runs} times in {time}s, Frequency: {frequency}");
Для проверки также запуск эффектов, которые вы можете использовать
acc.ProfileFirst(100*1000, "First call {0}s", "Method did run {runs} times in {time}s, Frequency: {frequency}");
Таким образом, вы можете легко проверить ваши методы, если указанный метод не пустой метод, который приведет к искажению таймингов, поскольку делегат вызов будет быть сопоставимым с вашим вызовом метода. Оригинальная идея - блог here.
Для более глубокого анализа времени вызова профилировщик тоже очень полезен. Вы должны попытаться использовать их, чтобы иметь возможность диагностировать более сложные проблемы.
using System;
using System.Globalization;
using System.Diagnostics;
namespace PerformanceTester
{
/// <summary>
/// Helper class to print out performance related data like number of runs, elapsed time and frequency
/// </summary>
public static class Extension
{
static NumberFormatInfo myNumberFormat;
static NumberFormatInfo NumberFormat
{
get
{
if (myNumberFormat == null)
{
var local = new CultureInfo("en-us", false).NumberFormat;
local.NumberGroupSeparator = " "; // set space as thousand separator
myNumberFormat = local; // make a thread safe assignment with a fully initialized variable
}
return myNumberFormat;
}
}
/// <summary>
/// Execute the given function and print the elapsed time to the console.
/// </summary>
/// <param name="func">Function that returns the number of iterations.</param>
/// <param name="format">Format string which can contain {runs} or {0},{time} or {1} and {frequency} or {2}.</param>
public static void Profile(this Func<int> func, string format)
{
Stopwatch watch = Stopwatch.StartNew();
int runs = func(); // Execute function and get number of iterations back
watch.Stop();
string replacedFormat = format.Replace("{runs}", "{3}")
.Replace("{time}", "{4}")
.Replace("{frequency}", "{5}");
// get elapsed time back
float sec = watch.ElapsedMilliseconds/1000.0f;
float frequency = runs/sec; // calculate frequency of the operation in question
try
{
Console.WriteLine(replacedFormat,
runs, // {0} is the number of runs
sec, // {1} is the elapsed time as float
frequency, // {2} is the call frequency as float
runs.ToString("N0", NumberFormat), // Expanded token {runs} is formatted with thousand separators
sec.ToString("F2", NumberFormat), // expanded token {time} is formatted as float in seconds with two digits precision
frequency.ToString("N0", NumberFormat)); // expanded token {frequency} is formatted as float with thousands separators
}
catch (FormatException ex)
{
throw new FormatException(
String.Format("The input string format string did contain not an expected token like "+
"{{runs}}/{{0}}, {{time}}/{{1}} or {{frequency}}/{{2}} or the format string " +
"itself was invalid: \"{0}\"", format), ex);
}
}
/// <summary>
/// Execute the given function n-times and print the timing values (number of runs, elapsed time, call frequency)
/// to the console window.
/// </summary>
/// <param name="func">Function to call in a for loop.</param>
/// <param name="runs">Number of iterations.</param>
/// <param name="format">Format string which can contain {runs} or {0},{time} or {1} and {frequency} or {2}.</param>
public static void Profile(this Action func, int runs, string format)
{
Func<int> f =() =>
{
for (int i = 0; i < runs; i++)
{
func();
}
return runs;
};
f.Profile(format);
}
/// <summary>
/// Call a function in a for loop n-times. The first function call will be measured independently to measure
/// first call effects.
/// </summary>
/// <param name="func">Function to call in a loop.</param>
/// <param name="runs">Number of iterations.</param>
/// <param name="formatFirst">Format string for first function call performance.</param>
/// <param name="formatOther">Format string for subsequent function call performance.</param>
/// <remarks>
/// The format string can contain {runs} or {0},{time} or {1} and {frequency} or {2}.
/// </remarks>
public static void ProfileWithFirst(this Action func, int runs, string formatFirst, string formatOther)
{
func.Profile(1, formatFirst);
func.Profile(runs - 1, formatOther);
}
}
}
Возможный дубликат [Время выполнения кода измерения] (https://stackoverflow.com/questions/16376191/measuring-code-execution-time) - Это на несколько дней старше, но [примечание] (https://meta.stackexchange.com/questions/10841/how-should-duplicate-questions-be-handled/). * Общее правило заключается в том, чтобы сохранить вопрос с наилучшим набором ответов и закрыть другой как дубликат . * " – ruffin