Обертывание синхронизации StopWatch с делегатом или лямбдой?

94
задан Servy 2 November 2016 в 13:12
поделиться

9 ответов

Как насчет того, чтобы расширить класс Секундомера?

public static class StopwatchExtensions
{
    public static long Time(this Stopwatch sw, Action action, int iterations)
    {
        sw.Reset();
        sw.Start(); 
        for (int i = 0; i < iterations; i++)
        {
            action();
        }
        sw.Stop();

        return sw.ElapsedMilliseconds;
    }
}

Тогда вызов это как это:

var s = new Stopwatch();
Console.WriteLine(s.Time(() => DoStuff(), 1000));

Вы могли добавить другую перегрузку, которая опускает "итеративный" параметр и называет эту версию с некоторым значением по умолчанию (как 1 000).

128
ответ дан Matt Hamilton 24 November 2019 в 06:05
поделиться

Вы могли попытаться писать дополнительный метод для любого класса, который Вы используете (или любой базовый класс).

у меня был бы вызов, будьте похожи:

Stopwatch sw = MyObject.TimedFor(1000, () => DoStuff(s));

Тогда дополнительный метод:

public static Stopwatch TimedFor(this DependencyObject source, Int32 loops, Action action)
{
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < loops; ++i)
{
    action.Invoke();
}
sw.Stop();

return sw;
}

Любой объект, происходящий из DependencyObject, может теперь назвать TimedFor (..). Функция может легко быть скорректирована для обеспечения возвращаемых значений через касательно параметрических усилителей.

-

, Если Вы не хотели, чтобы функциональность была связана с каким-либо классом / возражают, что Вы могли сделать что-то как:

public class Timing
{
  public static Stopwatch TimedFor(Action action, Int32 loops)
  {
    var sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < loops; ++i)
    {
      action.Invoke();
    }
    sw.Stop();

    return sw;
  }
}

Тогда Вы могли использовать его как:

Stopwatch sw = Timing.TimedFor(() => DoStuff(s), 1000);

Сбой, что, этот ответ похож на него, имеет некоторую достойную "универсальную" способность:

Переносящаяся синхронизация StopWatch с делегатом или лямбдой?

12
ответ дан Community 24 November 2019 в 06:05
поделиться

Я записал простой класс CodeProfiler некоторое время назад, который обернул Секундомер для легкого профилирования метода с помощью Действия: http://www.improve.dk/blog/2008/04/16/profiling-code-the-easy-way

Это также легко позволит Вам представлять многопоточный код. Следующий пример представит лямбду действия с 1-16 потоками:

static void Main(string[] args)
{
    Action action = () =>
    {
        for (int i = 0; i < 10000000; i++)
            Math.Sqrt(i);
    };

    for(int i=1; i<=16; i++)
        Console.WriteLine(i + " thread(s):\t" + 
            CodeProfiler.ProfileAction(action, 100, i));

    Console.Read();
}
7
ответ дан Jeff Atwood 24 November 2019 в 06:05
поделиться

Для принятия Вас просто нужна быстрая синхронизация одной вещи, это просто в использовании.

  public static class Test {
    public static void Invoke() {
        using( SingleTimer.Start )
            Thread.Sleep( 200 );
        Console.WriteLine( SingleTimer.Elapsed );

        using( SingleTimer.Start ) {
            Thread.Sleep( 300 );
        }
        Console.WriteLine( SingleTimer.Elapsed );
    }
}

public class SingleTimer :IDisposable {
    private Stopwatch stopwatch = new Stopwatch();

    public static readonly SingleTimer timer = new SingleTimer();
    public static SingleTimer Start {
        get {
            timer.stopwatch.Reset();
            timer.stopwatch.Start();
            return timer;
        }
    }

    public void Stop() {
        stopwatch.Stop();
    }
    public void Dispose() {
        stopwatch.Stop();
    }

    public static TimeSpan Elapsed {
        get { return timer.stopwatch.Elapsed; }
    }
}
4
ответ дан jyoung 24 November 2019 в 06:05
поделиться

Можно перегрузить много методов для покрытия различных случаев параметров, которые Вы могли бы хотеть передать лямбде:

public static Stopwatch MeasureTime<T>(int iterations, Action<T> action, T param)
{
    var sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < iterations; i++)
    {
        action.Invoke(param);
    }
    sw.Stop();

    return sw;
}

public static Stopwatch MeasureTime<T, K>(int iterations, Action<T, K> action, T param1, K param2)
{
    var sw = new Stopwatch();
    sw.Start();
    for (int i = 0; i < iterations; i++)
    {
        action.Invoke(param1, param2);
    }
    sw.Stop();

    return sw;
}

, С другой стороны, можно использовать делегата Func, если они должны возвратить значение. Можно также передать в массиве (или больше) параметров, если каждое повторение должно использовать уникальное значение.

2
ответ дан Morten Christiansen 24 November 2019 в 06:05
поделиться

Мне нравится использовать классы CodeTimer от Vance Morrison (один из чуваков производительности от.NET).

Он сделал сообщение на на его блоге названным" Имеющий размеры управляемый код быстро и easiliy: CodeTimers".

Это включает интересный материал, такой как MultiSampleCodeTimer. Это делает автоматическое вычисление среднего и стандартного отклонения и его также очень легкий распечатать Ваши результаты.

1
ответ дан Davy Landman 24 November 2019 в 06:05
поделиться

Для меня расширение кажется немного более интуитивным в int, вам больше не нужно создавать секундомер или беспокоиться о его сбросе.

Итак, у вас есть:

static class BenchmarkExtension {

    public static void Times(this int times, string description, Action action) {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        for (int i = 0; i < times; i++) {
            action();
        }
        watch.Stop();
        Console.WriteLine("{0} ... Total time: {1}ms ({2} iterations)", 
            description,  
            watch.ElapsedMilliseconds,
            times);
    }
}

С примером использования:

var randomStrings = Enumerable.Range(0, 10000)
    .Select(_ => Guid.NewGuid().ToString())
    .ToArray();

50.Times("Add 10,000 random strings to a Dictionary", 
    () => {
        var dict = new Dictionary<string, object>();
        foreach (var str in randomStrings) {
            dict.Add(str, null);
        }
    });

50.Times("Add 10,000 random strings to a SortedList",
    () => {
        var list = new SortedList<string, object>();
        foreach (var str in randomStrings) {
            list.Add(str, null);
        }
    });

Пример вывода:

Add 10,000 random strings to a Dictionary ... Total time: 144ms (50 iterations)
Add 10,000 random strings to a SortedList ... Total time: 4088ms (50 iterations)
2
ответ дан Sam Saffron 24 November 2019 в 06:05
поделиться

Вот что я использовал:

public class DisposableStopwatch: IDisposable {
    private readonly Stopwatch sw;
    private readonly Action<TimeSpan> f;

    public DisposableStopwatch(Action<TimeSpan> f) {
        this.f = f;
        sw = Stopwatch.StartNew();
    }

    public void Dispose() {
        sw.Stop();
        f(sw.Elapsed);
    }
}

Использование:

using (new DisposableStopwatch(t => Console.WriteLine("{0} elapsed", t))) {
  // do stuff that I want to measure
}
30
ответ дан 24 November 2019 в 06:05
поделиться

The StopWatch class does not need to be Disposed or Stopped on error. So, the simplest code to time some action is

public partial class With
{
    public static long Benchmark(Action action)
    {
        var stopwatch = Stopwatch.StartNew();
        action();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }
}

Sample calling code

public void Execute(Action action)
{
    var time = With.Benchmark(action);
    log.DebugFormat(“Did action in {0} ms.”, time);
}

I don't like the idea of including the iterations into the StopWatch code. You can always create another method or extension that handles executing N iterations.

public partial class With
{
    public static void Iterations(int n, Action action)
    {
        for(int count = 0; count < n; count++)
            action();
    }
}

Sample calling code

public void Execute(Action action, int n)
{
    var time = With.Benchmark(With.Iterations(n, action));
    log.DebugFormat(“Did action {0} times in {1} ms.”, n, time);
}

Here are the extension method versions

public static class Extensions
{
    public static long Benchmark(this Action action)
    {
        return With.Benchmark(action);
    }

    public static Action Iterations(this Action action, int n)
    {
        return () => With.Iterations(n, action);
    }
}

And sample calling code

public void Execute(Action action, int n)
{
    var time = action.Iterations(n).Benchmark()
    log.DebugFormat(“Did action {0} times in {1} ms.”, n, time);
}

I tested the static methods and extension methods (combining iterations and benchmark) and the delta of expected execution time and real execution time is <= 1 ms.

7
ответ дан 24 November 2019 в 06:05
поделиться
Другие вопросы по тегам:

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