【问题标题】:What is the best way to make a time measuring wrapper class for functions?为函数制作时间测量包装类的最佳方法是什么?
【发布时间】:2017-09-04 13:52:43
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    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(() =&gt; Function(a,b));而不是var results = await TimeMeasurer.Start(async () =&gt; 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;
        }
    }
    

    【讨论】:

    • 听起来不错!如果有更多解决方案,我很想听听。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-18
    • 1970-01-01
    • 2020-03-03
    • 1970-01-01
    • 2010-11-02
    • 2015-08-08
    相关资源
    最近更新 更多