Apr 10 2010

Wrap config settings for speedier access

Category: Tips and TricksJoeGeeky @ 08:11

Some time ago I wrote about creating custom configuration sections as an alternative to using appSettings. At the time, the focus revolved largely around the need for hierarchal and strongly typed configuration points, neither of which are really a feature of sections like appSettings. Although I feel like I'm picking on the poor little appSettings a little bit, if they're used incorrectly they can really hurt products that demand really high performance. Lets look at a common pattern applied to using appSettings:

string aString = ConfigurationManager.AppSettings["AString"];

The thing to remember is, these calls are bound to interactions with the applications configuration file and the ConfigurationManager does very little to mitigate the expense for this type of call. As an I/O bound resource, repeated calls can be very costly. Whether you're using appSettings or another config section, the only way to mitigate I/O bound costs is to cache your settings. There are lots of patterns to do this, here is a quick example of just one.

Lets start with an interface representing our configuration settings. Strictly speaking an interface is not required, but makes it easier to inject configurations using the Dependency Injection pattern later on.

public interface IConfig
{
    string AString { get; }
    bool BBoolean { get; }
    int CInt { get; }
    DateTime DDate { get; }
}

Now lets implement the interface. In doing so we need to accomplish the following:

  • Load configuration points from file
  • Cache the configuration results
  • Provide a mechanism to refresh the cached configuration

public class Config : IConfig
{
    private static IConfig _config;

    public Config()
    {
        AString = ConfigurationManager.AppSettings["AString"];
        BBoolean = Convert.ToBoolean(ConfigurationManager.AppSettings["BBoolean"]);
        CInt = Convert.ToInt32(ConfigurationManager.AppSettings["CInt"]);
        DDate = Convert.ToDateTime(ConfigurationManager.AppSettings["DDate"]);
    }

    #region IConfig Members

    public string AString { get; private set; }
    public bool BBoolean { get; private set; }
    public int CInt { get; private set; }
    public DateTime DDate { get; private set; }

    #endregion

    public static IConfig Current
    {
        get
        {
            if (_config == null)
                _config = new Config();

            return _config;
        }
    }

    public static void Refresh()
    {
        _config = new Config();
    }
}

As you can see this is essentially a singleton pattern. While this may seem a little boring, its clean, testable, and can be extended to provide a wide range of related functionality. The real test is whether or not this is actually any faster... Creating a simple loop test we can get a sense of how this stacks up.  

private static void Main(string[] args)
{
    const int MaxReads = int.MaxValue / 2;
    var watch = new Stopwatch();
 
    Console.WriteLine();
 
    watch.Start();
    for (int i = 0; i < MaxReads; i++)
    {
        IConfig config = Config.Current;
 
        string AString = config.AString;
        bool BBoolean = config.BBoolean;
        int CInt = config.CInt;
        DateTime DDate = config.DDate;
    }
    watch.Stop();
 
    Console.WriteLine("Using Cached Config - Rate/Sec: \t{0}", MaxReads / watch.Elapsed.TotalSeconds);
 
    watch.Reset();
    watch.Start();
    for (int i = 0; i < MaxReads; i++)
    {
        string AString = ConfigurationManager.AppSettings["AString"];
        bool BBoolean = Convert.ToBoolean(ConfigurationManager.AppSettings["BBoolean"]);
        int CInt = Convert.ToInt32(ConfigurationManager.AppSettings["CInt"]);
        DateTime DDate = Convert.ToDateTime(ConfigurationManager.AppSettings["DDate"]);
    }
    watch.Stop();
 
    Console.WriteLine("Using ConfigurationManager - Rate/Sec: \t{0}", MaxReads / watch.Elapsed.TotalSeconds);
    Console.ReadLine();
}

Here are the results...

As you can see, the difference in performance can be dramatic. Although I used appSettings as the center of this example, the same basic problem exists for any configuration section (Ex. connection strings, custom sections, etc...). Hope this helps.

Tags: ,

Comments

1.
trackback DotNetKicks.com says:

Wrap config settings for speedier access

You've been kicked (a good thing) - Trackback from DotNetKicks.com

2.
Bennie Lino Bennie Lino United States says:

This is actually my first time here, really nice looking blog. I found a lot of fascinating things in your blog particularly it's discussion. From all the comments on your posts, it looks like this is a extremely popular site. Keep up the great work.

3.
Romeo Asar Romeo Asar United States says:

This is my first time i visit here. I found so many interesting stuff in your blog especially its discussion. From the tons of comments on your articles, I guess I am not the only one having all the enjoyment here keep up the good work.

4.
Librada Mallone Librada Mallone Poland says:

Good read, I can't wait for the rest

Comments are closed