Lets say you want to execute a specific logging function based on a log level. Amongst others you could use a switch- or if statements or use a generic dictionary containing the functions to call.

 

In mine code the generic dictionary has the advantage of being more testable, so I wanted to figure out what the performance impact of this dictionary lookup was. So I wrote a little test.

Each test will execute a log function 1 million times.

 

 

Executing 1.000.000 times:

Switch: 374ms

If: 387ms (3% slower)

Dictionary: 393ms (5% slower)

 

 

In my case this was enough to convince me to use the generic dictionary lookup for better testability.

 

namespace PTB.Cs.Test.Research
{
using System;
using System.Collections.Generic;
using System.IO;
using Xunit;

public class RliTester
{
    private string _message;

    private readonly Dictionary<Levels, Action<string>> _logFunctions;
    public RliTester()
    {
        _logFunctions = new Dictionary<Levels, Action<string>>
        {
            { Levels.Debug, Debug },
            { Levels.Error, Error },
            { Levels.Info, Info },
            { Levels.Warning, Warning },
        };    
    }

    public void Debug(string message)
    {
        _message = message;
    }

    public void Error(string message)
    {
        _message = message;
    }

    public void Info(string message)
    {
        _message = message;
    }

    public void Warning(string message)
    {
        _message = message;
    }

    public void ExecuteFunctionBySwitch(Levels level, string message)
    {
        switch (level)
        {
            case Levels.Debug:
                Debug(message);
                break;
            case Levels.Error:
                Error(message);
                break;
            case Levels.Info:
                Info(message);
                break;
            case Levels.Warning:
                Warning(message);
                break;
        }
    }

    public void ExecuteFunctionByIf(Levels level, string message)
    {
        if (level == Levels.Debug)
        {
            Debug(message);
        }

        if (level == Levels.Error)
        {
            Error(message);
        }

        if (level == Levels.Info)
        {
            Info(message);
        }

        if (level == Levels.Warning)
        {
            Warning(message);
        }
    }


    public void ExecuteFunctionByDictionairyLookup(Levels level, string message)
    {
        _logFunctions[level].Invoke(message);
    }

    [Fact]
    public void Test_performance_ExecuteFunctionBySwitch()
    {
        var watch = new System.Diagnostics.Stopwatch();
        watch.Start();

        for(int i = 0; i < 1000000; i++)
        {
            ExecuteFunctionBySwitch(Levels.Info, string.Format("This is info message [{0}].", i));
        }

        watch.Stop();
        System.Console.WriteLine(watch.Elapsed.TotalMilliseconds);

        // Result: 374ms
    }

    [Fact]
    public void Test_performance_ExecuteFunctionIf()
    {
        var watch = new System.Diagnostics.Stopwatch();
        watch.Start();
            
        for (int i = 0; i < 1000000; i++)
        {
            ExecuteFunctionByIf(Levels.Info, string.Format("This is info message [{0}].", i));
        }

        watch.Stop();
        System.Console.WriteLine(watch.Elapsed.TotalMilliseconds);

        // Result: 387ms
    }

    [Fact]
    public void Test_performance_ExecuteFunctionByDictionairyLookup()
    {
        var watch = new System.Diagnostics.Stopwatch();
        watch.Start();

        for (int i = 0; i < 1000000; i++)
        {
            ExecuteFunctionByDictionairyLookup(Levels.Info, string.Format("This is info message [{0}].", i));
        }

        watch.Stop();
        System.Console.WriteLine(watch.Elapsed.TotalMilliseconds);

        // Result: 393ms
    }

        
}

/// <summary>
/// Determines the level of the logging.
/// </summary>
public enum Levels
{
    Error = 1,
    Warning = 2,
    Info = 3,
    Debug = 4
}
}

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.