What's the best way to make a wrapper class measurement for functions?

I want to start measuring the time it takes to run a function in my program in multiple locations.

Working with StopWatch

seemed a little messy in the code, so I decided to wrap it up.

This is what I need:

  • the function will receive an asynchronous function, which may or may not have a return value
  • I need to exit the function two things: the return value, if it exists, and the time in seconds it took to run

I want to find a readable and stable solution as it will be used across multiple projects.


this is what i have done so far:

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

      

if there is no better solution.

  • Is there a way to merge between the two functions? (one to include the return value and the second to get invalid functions)
  • Is there a way to return something clearer than a tuple? I believe it is useless to deal with

edit: The class call I made looks great too.

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

      


EDIT: I decided to give this idea. It's too messy. Eventually using StopWatch

+3


source to share


1 answer


In your first point, there isn't much you can do to combine functions, there isn't much logic to combine.

For your second point, I would make two custom classes to hold the result. You can get fancy and do some inheritance and return the entire task object rather than just the result if someone wants to see some properties of the returned task.

Finally, there is no reason why your function should be an instance, the whole class can be made static.

Here's an example that contains the changes I suggested.



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

      

Here is an example using it , please note that I needed to do var results = await TimeMeasurer.Start(() => Function(a,b));

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

      

0


source







All Articles