当前位置:  开发笔记 > 编程语言 > 正文

使用委托或lambda包装StopWatch计时?

如何解决《使用委托或lambda包装StopWatch计时?》经验,为你挑选了5个好方法。

我正在写这样的代码,做一些快速和肮脏的时间:

var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000; i++)
{
    b = DoStuff(s);
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);

肯定有一个方法来调用此位的计时码作为花式schmancy .NET 3.0的λ,而不是(上帝保佑)剪切和粘贴了几次和更换DoStuff(s)DoSomethingElse(s)

我知道它可以作为一个Delegate但我想知道lambda方式.



1> Matt Hamilto..:

如何扩展秒表类?

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));

您可以添加另一个省略"iterations"参数的重载,并使用一些默认值(如1000)调用此版本.


@Jay我同意Enumerable.Range的"foreach"看起来更"现代",但是我的测试显示它比大量计数的"for"循环慢大约四倍.因人而异.
@Matt Hamilton:我不这么认为 - 他们是为现有的类添加(逻辑上)实例方法.但是,这不再是一个比"Stopwatch.StartNew"更多的实例方法,这是一个静态的原因.C#缺乏向现有类添加静态方法的能力(与F#不同),所以我理解这样做的冲动,但它仍然在我的口中留下了不好的味道.
您可能希望将sw.Start()替换为sw.StartNew(),以防止意外增加每次连续调用s.Time()所花费的时间,重用相同的Stopwatch实例.
-1:在这里使用类扩展没有任何意义。时间是一种静态方法,会丢弃sw中的所有现有状态,因此将其作为实例方法引入看起来很花哨。
@ildjam我很欣赏你留下了一条解释你的downvote的评论,但我认为你误解了扩展方法背后的想法.

2> Mauricio Sch..:

这是我一直在使用的:

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

    public DisposableStopwatch(Action 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
}



3> Mark Ingram..:

您可以尝试为您正在使用的任何类(或任何基类)编写扩展方法.

我打电话看起来像:

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(..).可以通过ref参数轻松调整该函数以提供返回值.

-

如果您不希望将功能绑定到任何类/对象,您可以执行以下操作:

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);

如果做不到这一点,这个答案看起来有一些不错的"通用"能力:

使用委托或lambda包装StopWatch计时?



4> Mark S. Rasm..:

我前段时间编写了一个简单的CodeProfiler类,它使用Action包裹了秒表以轻松地分析方法:http: //www.improve.dk/blog/2008/04/16/profiling-code-the-easy-way

它还可以让您轻松地分析多线程代码.以下示例将使用1-16个线程分析动作lambda:

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();
}



5> Anthony Mast..:

StopWatch类并不需要是DisposedStopped出错.所以,最简单的代码有些动作

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

样本调用代码

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

我不喜欢将迭代包含在StopWatch代码中的想法.您始终可以创建另一个处理执行N迭代的方法或扩展.

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

样本调用代码

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);
}

这是扩展方法版本

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);
    }
}

并调用代码示例

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

我测试了静态方法和扩展方法(结合迭代和基准测试),预期执行时间和实际执行时间的增量<= 1 ms.

推荐阅读
低调pasta_730
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有