Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用代理或lambda包装秒表计时?_C#_.net_Delegates_Lambda - Fatal编程技术网

C# 用代理或lambda包装秒表计时?

C# 用代理或lambda包装秒表计时?,c#,.net,delegates,lambda,C#,.net,Delegates,Lambda,我正在写这样的代码,做一些快速而肮脏的计时: 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 lambda,而不是上帝禁止将其剪切粘贴几次并用dosomethingel

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

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 lambda,而不是上帝禁止将其剪切粘贴几次并用dosomethingeles替换dostuff


我知道它可以作为一个委托来完成,但我想知道lambda的方法。

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

我会让电话看起来像:

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;
}
如果做不到这一点,这个答案看起来有一些不错的通用能力:


扩展秒表类怎么样

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

您可以添加另一个重载,该重载将忽略迭代参数,并使用一些默认值(如1000)调用此版本。

您可以重载许多方法,以涵盖可能要传递给lambda的参数的各种情况:

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委托。如果每次迭代都必须使用唯一的值,则还可以传入一个数组或多个参数。

我不久前编写了一个简单的CodeProfiler类,它包装了秒表,以便使用操作轻松地分析方法:

它还可以轻松地分析多线程代码。以下示例将使用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();
}

我喜欢使用万斯·莫里森(Vance Morrison)的CodeTimer类。万斯·莫里森是.NET中的一个性能专家

他在自己的博客上发表了一篇题为


它包括一些很酷的东西,比如多采样代码计时器。它可以自动计算平均值和标准偏差,还可以很容易地打印出结果。

假设您只需要对一件事情进行快速计时,这很容易使用

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

对我来说,扩展在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);
    }
}

以下是我一直在使用的:

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);
    }
}
StopWatch类不需要在出错时释放或停止。因此,对某些操作计时的最简单代码是

调用代码示例

public void Execute(Action action)
{
    var time = With.Benchmark(action);
    log.DebugFormat(“Did action in {0} ms.”, time);
}
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 void Execute(Action action, int n)
{
    var time = action.Iterations(n).Benchmark()
    log.DebugFormat(“Did action {0} times in {1} ms.”, n, time);
}
我不喜欢在秒表代码中包含迭代的想法。您始终可以创建另一个方法或扩展来处理N次迭代的执行

public partial class With
{
    public static void Iterations(int n, Action action)
    {
        for(int count = 0; count < n; count++)
            action();
    }
}
以下是扩展方法的版本

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)
{
    var time = With.Benchmark(action);
    log.DebugFormat(“Did action in {0} ms.”, time);
}
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 void Execute(Action action, int n)
{
    var time = action.Iterations(n).Benchmark()
    log.DebugFormat(“Did action {0} times in {1} ms.”, n, time);
}

我测试了结合迭代和基准测试的静态方法和扩展方法,预期执行时间和实际执行时间的增量很酷,但我不在乎它与特定类或基类的联系方式;它可以更一般地完成吗?就像在为其编写扩展方法的MyObject类中一样?它可以很容易地进行更改以扩展继承树中的对象类或其他类。我考虑的是更静态的,比如不绑定到任何特定的对象或类。。时间和计时是一种通用的工具,第二个版本更像我想的,+1,但我给了Matt第一个版本。你可能想替换sw。从sw.StartNew开始,以防止意外增加s.time每次连续调用的运行时间,重复使用同一个秒表实例。@Jay我同意foreach和Enumerable.Range看起来有点现代,但我的测试表明,在大计数上,它比for循环慢四倍左右。YMMV.-1:在这里使用类扩展毫无意义。时间的行为就像一个静态方法,丢弃了sw中所有现有的状态,所以将其作为实例方法引入看起来很花哨。@ildjam我很感激你留下一条评论解释你的否决票,但是我认为你误解了扩展方法背后的想法。@Matt Hamilton:我不这么认为-它们是用于向现有类添加逻辑实例方法的。但是,与Stopwatch.StartNew相比,这不再是一个实例方法,因为它是静态的。与F不同,C缺乏向现有类添加静态方法的能力,因此我理解这样做的冲动,但它仍然让我口齿不清。扩展方法版本让我口水直流这是我见过的最好的解决方案!没有扩展,所以它可以在许多类上使用,而且非常干净!我不确定我是否正确地得到了用法示例。当我尝试使用Console.WriteLine在//do stuff下测试我想要测量的内容时,编译器一点也不高兴。你应该在那里做普通表达式和语句吗?@Tim-我肯定你已经解决了,但是using语句缺少一个括号
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);
}
public static class StopWatchExtensions
{
    public static async Task<TimeSpan> LogElapsedMillisecondsAsync(
        this Stopwatch stopwatch,
        ILogger logger,
        string actionName,
        Func<Task> action)
    {
        stopwatch.Reset();
        stopwatch.Start();

        await action();

        stopwatch.Stop();

        logger.LogDebug(string.Format(actionName + " completed in {0}.", stopwatch.Elapsed.ToString("hh\\:mm\\:ss")));

        return stopwatch.Elapsed;
    }
}