Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Tuesday, May 27, 2008

The Myth of for being faster than foreach

You probably, like me, heard this so many times that for is faster than foreach and you should use it whenever you can. Well, today I wanted to know how much this is true so I did a little test (find below the test and results). As you can see in the results of the test they are both identical but as I find using foreach is much more convenient for many reasons (including thread safety in some scenarios) so it makes more sense to use foreach whenever possible.

More details:

The release build was used in the test
Software used in the test:
  • Windows XP Pro SP2
  • .NET Framework 2.0

The specs of my computer (where the test was done) are:
  • CPU Intel 1.6GHz Dual Core
  • 1024 MB RAM


Used Code
using System;
using System.Collections.Generic;
using System.Text;

namespace for_vs_foreach
{
    class Program
    {
        static void Main(string[] args)
        {
            const int LOOP_COUNT = 10000000;
            int myVar;
            MyCustomObject[] customObjects = new MyCustomObject[LOOP_COUNT];
            for (int i = 0; i < LOOP_COUNT; i++)
            {
                customObjects[i] = new MyCustomObject(i);
            }

            System.Threading.Thread.Sleep(1000);

            // foreach
            //
            DateTime beforeForeach = DateTime.Now;
            foreach (MyCustomObject customObject in customObjects)
            {
                myVar = customObject.Var;
            }
            DateTime afterForeach = DateTime.Now;

            // for
            //
            DateTime beforeFor = DateTime.Now;
            for (int i = 0; i < LOOP_COUNT; i++)
            {
                myVar = customObjects[i].Var;
            }
            DateTime afterFor = DateTime.Now;

            Console.WriteLine("{0} (foreach test results)", afterForeach.Subtract(beforeForeach));
            Console.WriteLine("{0} (for test results)", afterFor.Subtract(beforeFor));
            Console.Read();
        }
    }

    public class MyCustomObject
    {
        public MyCustomObject(int var)
        {
            _var = var;
        }

        private int _var;
        public int Var
        {
            get
            {
                return _var;
            }
            set
            {
                _var = value;
            }
        }
    }
}
Results: 00:00:00.0625000 (foreach test results)
00:00:00.0625000 (for test results)

Saturday, May 10, 2008

Efficiently Copying Items from One Array to Another in C# (Also generally in .NET)

I've been searching recently for an efficient way in C# to copy items from an array to another. At first it seemed that efficient way simply didn't exist. In C++ you can do this very easily by copying the memory block using memcpy() or memmove() but in C# you can't do this in a safe way (sure you can write some unsafe code but this is not really what I wanted, I just wanted to do it the 'clean and safe way'). Anyway, my options were to use Array.Copy() or a for loop (iterate through the source array and copy the items to the destination array). Unfortunately the documentation for Array.Copy() clearly states that it's an O(n) operation where n is length, so, it seemed that the for loop and Array.Copy() were almost equivalent so I decided I could use any of them as it wouldn't make any real difference (my decision was based on what's written in the documentation about Array.Copy() being an O(n) operation)

Anyway, today I was using .NET Refelctor to view the code for List<T>.ToArray(), I found that the Array.Copy() was used in the code, see below the code for List<T>.ToArray() copied from .NET Reflector:

public T[] ToArray()
{
    T[] destinationArray = new T[this._size];
    Array.Copy(this._items, 0, destinationArray, 0, this._size);
    return destinationArray;
}

So, I wanted to have a look on Array.Copy(), this is how it shows in .NET Refelctor:

[ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
public static void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length)
{
    Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length, false);
}

The code for Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length, false); can't be viewed using .NET Reflector, here's what you get:

[MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.MayCorruptInstance, Cer.MayFail)]
internal static extern void Copy(Array sourceArray, int sourceIndex, Array destinationArray, int destinationIndex, int length, bool reliable);

To make a long story short I just was curious to see whether using Array.Copy() is really equivalent to using a simple for loop, so, motivated by my inability to view the code for Array.Copy(),I decided to do my own testing (see the code and results below). Well, despite what's written in the documentation about Array.Copy() being an O(n) operation, Array.Copy() was 10 times faster on my computer! So my guess is that it internally uses some memory copying so it's not really an O(n) operation.

Update:

Just to be clear, when I said the operation is not O(n), I was referring to the implementation not using a for loop to copy the items (ie. from the performance point of view). I realize it's technically incorrect to say it's not O(n). My apology for the confusion.

More details:

The release build was used in the test
Software used in the test:
  • Windows XP Pro SP2
  • .NET Framework 2.0

The specs of my computer (where the test was done) are:
  • CPU Intel 1.6GHz Dual Core
  • 1024 MB RAM


Used Code
using System;
using System.Collections.Generic;
using System.Text;

namespace array_copy
{
    class Program
    {
        static void Main(string[] args)
        {
            const int ArraySize = 5000;
            const int LoopCount = 100000;

            MyCustomObject[] customObjects1 = new MyCustomObject[ArraySize];
            MyCustomObject[] customObjects2 = new MyCustomObject[ArraySize];
            for (int i = 0; i < ArraySize; i++)
            {
                customObjects1[i] = new MyCustomObject(i);
                customObjects2[i] = new MyCustomObject(i);
            }

            // Array.Copy()
            //
            DateTime beforeArrayCopy = DateTime.Now;
            for (int j = 0; j < LoopCount; j++)
            {
                Array.Copy(customObjects1, 0, customObjects2, 1, customObjects1.Length - 1);
            }
            DateTime afterArrayCopy = DateTime.Now;

            // For Loop Copy
            //
            DateTime beforeForLoopCopy = DateTime.Now;
            for (int j = 0; j < LoopCount; j++)
            {
                int length = customObjects1.Length - 1;
                for (int i = 0; i < length; i++)
                {
                    customObjects2[i + 1] = customObjects1[i];
                }
            }
            DateTime afterForLoopCopy = DateTime.Now;

            Console.WriteLine("{0} Array.Copy()", afterArrayCopy.Subtract(beforeArrayCopy));
            Console.WriteLine("{0} For Loop Copy", afterForLoopCopy.Subtract(beforeForLoopCopy));

            Console.Read();
        }
    }

    public class MyCustomObject
    {
        public MyCustomObject(int var)
        {
            _var = var;
        }

        private int _var;
        public int Var
        {
            get
            {
                return _var;
            }
        }
    }
}
Results: 00:00:00.5937500 Array.Copy()
00:00:04.9062500 For Loop Copy

Thursday, April 24, 2008

If you're Worried About Performance, Avoid Using Type Initializers (aka static constructors)

I'm currently trying to write a highly scalable web application (using C# and .NET Framework 2.0), so, I simply trying to squeeze every drop of performance of the CPU, the DB .. etc. I'm doing a lot of performance testing to everything I use in my application. In my application, I'm using static constructors heavily as they seem to make things easier, well, this is until I realized that they really affect performance! Actually, I discovered this by accident while doing another test. I wanted to test the performance of using nested static classes vs. using singletons, in the process I used a couple of static constructors in the classes (see the code below), the point was to use the static constructor to initiate the variable used for holding the singleton object reference so that we can remove the lazy loading if condition which I expected it would improve performance, well, this is what I thought but the result was surprising to me, the classes that have static constructors take much more time to be accessed than those that don't have static constructors (see the results at the end of this post). My wild guess is that every time a class with a static constructor is accessed the runtime checks whether the static constructor was called or not which causes the performance hit. Without further ado, here's the code below and the results of running the test on my computer .

More details:

I used the release build in the test (not the debug build as it very often gives very wrong results)
Software used in the test:
  • Windows XP Pro SP2
  • .NET Framework 2.0

The specs of my computer (where the test was done) are:
  • CPU Intel 1.6GHz Dual Core
  • 1024 MB RAM


Used Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace singleton_vs_nested_classes
{
    class Program
    {
        static void Main(string[] args)
        {
            const int LOOP_COUNT = 1000000000;
            int tempVar = 0;
            Thread.Sleep(3000);

            // TestStatic
            //
            tempVar = TestStatic.TestVar;
            DateTime beforeTestStatic = DateTime.Now;
            for (int i = 0; i < LOOP_COUNT; i++)
            {
                tempVar = TestStatic.TestVar;
            }
            DateTime afterTestStatic = DateTime.Now;

            // TestStaticWithTypeInitializer
            //
            tempVar = TestStaticWithTypeInitializer.TestVar;
            DateTime beforeTestStaticWithTypeInitializer = DateTime.Now;
            for (int i = 0; i < LOOP_COUNT; i++)
            {
                tempVar = TestStaticWithTypeInitializer.TestVar;
            }
            DateTime afterTestStaticWithTypeInitializer = DateTime.Now;

            // TestNested
            //
            tempVar = TestNested.MyNestedClass.TestVar;
            DateTime beforeTestNested = DateTime.Now;
            for (int i = 0; i < LOOP_COUNT; i++)
            {
                tempVar = TestNested.MyNestedClass.TestVar;
            }
            DateTime afterTestNested = DateTime.Now;

            // TestSingltonLazyLoading
            //
            tempVar = TestSingltonLazyLoading.Singlton.TestVar;
            DateTime beforeTestSingltonLazyLoading = DateTime.Now;
            for (int i = 0; i < LOOP_COUNT; i++)
            {
                tempVar = TestSingltonLazyLoading.Singlton.TestVar;
            }
            DateTime afterTestSingltonLazyLoading = DateTime.Now;

            // TestSingltonInitInTypeInitliazer
            //
            tempVar = TestSingltonInitInTypeInitliazer.Singlton.TestVar;
            DateTime beforeTestSingltonInitInTypeInitliazer = DateTime.Now;
            for (int i = 0; i < LOOP_COUNT; i++)
            {
                tempVar = TestSingltonInitInTypeInitliazer.Singlton.TestVar;
            }
            DateTime afterTestSingltonInitInTypeInitliazer = DateTime.Now;

            // Show results
            //
            Console.WriteLine("{0} TestStatic", afterTestStatic.Subtract(beforeTestStatic));
            Console.WriteLine("{0} TestStaticWithTypeInitializer", afterTestStaticWithTypeInitializer.Subtract(beforeTestStaticWithTypeInitializer));
            Console.WriteLine("{0} TestNested", afterTestNested.Subtract(beforeTestNested));
            Console.WriteLine("{0} TestSingltonLazyLoading", afterTestSingltonLazyLoading.Subtract(beforeTestSingltonLazyLoading));
            Console.WriteLine("{0} TestSingltonInitInTypeInitliazer", afterTestSingltonInitInTypeInitliazer.Subtract(beforeTestSingltonInitInTypeInitliazer));
            Console.Read();
        }
    }

    public static class TestStatic
    {
        private static int _testVar = 5;
        public static int TestVar
        {
            get
            {
                return _testVar;
            }
        }
    }

    public static class TestStaticWithTypeInitializer
    {
        static TestStaticWithTypeInitializer()
        {
            _testVar = 5;
        }

        private static int _testVar;
        public static int TestVar
        {
            get
            {
                return _testVar;
            }
        }
    }

    public static class TestNested
    {
        public static class MyNestedClass
        {
            private static int _testVar = 5;
            public static int TestVar
            {
                get
                {
                    return _testVar;
                }
            }
        }
    }

    public static class TestSingltonLazyLoading
    {
        private static TestSinglton _singltonInstance;
        public static TestSinglton Singlton
        {
            get
            {
                if (_singltonInstance == null)
                {
                    _singltonInstance = new TestSinglton(5);
                }
                return _singltonInstance;
            }
        }
    }

    public static class TestSingltonInitInTypeInitliazer
    {
        static TestSingltonInitInTypeInitliazer()
        {
            _singltonInstance = new TestSinglton(5);
        }

        private static TestSinglton _singltonInstance;
        public static TestSinglton Singlton
        {
            get
            {
                return _singltonInstance;
            }
        }
    }

    public class TestSinglton
    {
        public TestSinglton(int testVar)
        {
            _testVar = testVar;
        }

        private int _testVar;
        public int TestVar
        {
            get
            {
                return _testVar;
            }
        }
    }
}
Results: 00:00:01.2656250 TestStatic
00:00:12.8437500 TestStaticWithTypeInitializer
00:00:01.2812500 TestNested
00:00:03.2187500 TestSingltonLazyLoading
00:00:09.3125000 TestSingltonInitInTypeInitliazer