我正在写这样的代码,做一些快速和肮脏的时间:
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方式.
如何扩展秒表类?
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)调用此版本.
这是我一直在使用的:
public class DisposableStopwatch: IDisposable { private readonly Stopwatch sw; private readonly Actionf; 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 }
您可以尝试为您正在使用的任何类(或任何基类)编写扩展方法.
我打电话看起来像:
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计时?
我前段时间编写了一个简单的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(); }
本StopWatch
类并不需要是Disposed
或Stopped
出错.所以,最简单的代码时有些动作是
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.