c# - 为函数制作时间测量包装类的最佳方法是什么?

标签 c# asp.net .net async-await stopwatch

我想开始测量函数在我的程序中的多个位置运行所花费的时间。

处理 StopWatch 的代码似乎有点困惑,所以我决定将其包装起来。

这些是我需要的东西:

  • 该函数将接收一个可能有也可能没有返回值的异步函数
  • 我需要从函数中取出两件事:返回值(如果存在)和它运行所花费的时间(以秒为单位)

我想找到一个可读且可持续的解决方案,因为它将用于多个项目。


这是我到目前为止所做的:

public class TimeMeasurer 
{
private readonly Stopwatch _stopWatch;

public TimeMeasurer()
{
    _stopWatch = new Stopwatch();
}

public async Task<Tuple<double, TReturn>> Start<TReturn>(Func<Task<TReturn>> function)
{
    try
    {
        _stopWatch.Start();
        var val = await function();
        var took = _stopWatch.Elapsed.TotalSeconds;

        return Tuple.Create(took, val);
    }
    finally
    {
        _stopWatch.Stop();
        _stopWatch.Reset();
    }
}

public async Task<double> Start(Func<Task> function)
{
    try
    {
        _stopWatch.Start();
        await function();
        var took = _stopWatch.Elapsed.TotalSeconds;

        return took;
    }
    finally
    {
        _stopWatch.Stop();
        _stopWatch.Reset();
    }
}
}

如果没有更好的解决方案..

  • 有没有办法合并这两个功能? (一个包含返回值,第二个获取 void 函数)
  • 有没有办法返回比元组更清晰的东西?我觉得处理起来有点麻烦

编辑:调用我创建的类看起来也不太好..

var tuple = await _timeMeasurer.Start(async () => await function(param1, param2));

编辑:我决定放弃这个想法。太乱了。最后我使用 StopWatch

最佳答案

对于你的第一点,你可以做的不多,可以组合这些功能,只是没有太多的逻辑可以组合。

对于你的第二点,我会创建两个自定义类来保存结果。您也可以想象并进行一些继承,并返回整个任务对象,而不仅仅是结果,以防有人想查看返回任务的某些属性。

最后,你的函数没有理由应该是一个实例,整个类都可以是静态的。

这是一个包含我建议的更改的示例。

public class TimeMeasurerResult
{
    protected readonly Task _task;
    private readonly TimeSpan _duration;

    public TimeMeasurerResult(Task task, TimeSpan duration)
    {
        _task = task;
        _duration = duration;
    }

    public Task Task {get { return _task;}}
    public TimeSpan Duration {get {return _duration;}}
}

public class TimeMeasurerResult<T> : TimeMeasurerResult
{    
    public TimeMeasurerResult(Task<T> task, TimeSpan duration)
        :base(task, duration)
    {
    }

    public T Result {get { return ((Task<T>)_task).Result;}}
}

public static class TimeMeasurer 
{    
    public static async Task<TimeMeasurerResult<TReturn>> Start<TReturn>(Func<Task<TReturn>> function)
    {
        var stopWatch = Stopwatch.StartNew();
        var task = function();
        await task;
        var took = stopWatch.Elapsed;

        return new TimeMeasurerResult<TReturn>(task, took);
    }

    public static async Task<TimeMeasurerResult> Start(Func<Task> function)
    {
        var stopWatch = Stopwatch.StartNew();
        var task = function();
        await task;
        var took = stopWatch.Elapsed;

        return new TimeMeasurerResult(task, took);
    }    
}

这是一个 using it 的例子,注意我只需要做 var results = await TimeMeasurer.Start(() => Function(a,b)); 而不是 var results = await TimeMeasurer.Start(async () => await Function(a,b));

public class Program
{
    public static void Main()
    {
        AsyncMain().Wait();
    }

    public static async Task AsyncMain()
    {
        int a = 500;
        int b = 10;
        var results = await TimeMeasurer.Start(() => Function(a,b));
        Console.WriteLine("Waited: {0}", results.Duration.TotalSeconds);
        Console.WriteLine("Result: {0}", results.Result);
    }

    public static async Task<int> Function(int a, int b)
    {
        var total = a + b;
        await Task.Delay(total);
        return total;
    }
}

关于c# - 为函数制作时间测量包装类的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43307599/

相关文章:

c# - 使用 Roslyn 编译 xaml

asp.net - 为什么 Visual Studio 在错误的文件夹中查找我的 gulpfile?

c# - AvalonEdit:级联高亮着色器

c# - 在 .aspx 和 .ascx 页面中捕获异常

c# - 单元格边框导致日历变大

c# - 如何根据 dtd 验证 xml

c# - 如何在IIS中下载文件?

c# - Protobuf-net 似乎是对值类型进行包装。事实是这样吗?

c# - 从 vb.net 调用 WCF 时如何增加 MaxReceivedMessageSize

asp.net - 在内框架中加载内容时显示加载指示器