Logo: C# Computing
 
Web CsharpComputing.com

C# Tutorial Lesson 23: Code optimization notes

In life of every program, there is time when it starts running too slow for the hardware it is on. This makes into an unhappy situation: customers are not happy, your boss is not happy, and who knows if you are still going to get a raise despite of that :-). Heaving read a few million lines of C# code, I came up with these optimization benchmarks that help to significanlty improve code performance through simple changes.

1. Boxing and unboxing

static private void TestBoxingAndUnboxing()
{
int i = 123;
object o = i; // Implicit boxing

i = 456; // Change the contents of i

int j = (int)o; // Unboxing (may throw an exception if the types are incompatible)
}

//this function is about 2*Log(N) faster
static private void TestNoBoxingAndUnboxing()
{
int i = 123;

i = 456; // Change the contents of i

int j = i; // Compatible types
}

2. Collections


//Using actual size for data rather than some default size increases performance up to 50%
ht = new Hashtable(count); // Creates an Hashtable using size = Count
LoadData(ht, count);


// Display results
Display.Show(1, "Elapsed time: " + t.ElapsedTime.ToString() + " ms \n", 0);

// End of the demo
Display.Show(-1, "Collections demo end.\n", 1);
}

static private void LoadData(Hashtable ht, int Count)
{
// Fill the employee collection with data
for (int i = 0; i < Count; i++)
{
Employee employee = new Employee(i, "Employee" + i.ToString());

ht.Add(i, employee);
}

3. Exceptions


//throwing and catching an exception is 1000 slower than checking for an error code
static void FunctionThatThrows()
{
throw new Exception();
}

static int FunctionThatReturnsErrorCode()
{
return -1;
}

4. Loops

//for loop is twice faster than foreach loop
static private void TestForeachLoop(ArrayList List)
{
int id = 0;

foreach (int i in List)
{
// Do something with the object ...
id = i;
}
}

static private void TestForLoop(ArrayList List)
{
int id = 0;
int count = List.Count;

for (int i = 0; i < List.Count; i++)
{
// Do something with the object ...
id = (int)List[i];
}
}

5. Garbage collection

//80% slower than doing nothing
static private void Test(int count)
{
DisposableObject []obj = new DisposableObject[count];
for(int i=0;i<count;i++)
obj[i]=new DisposableObject();

// Do some work with the object here ...

// Release the object.
obj = null;

// Forcing garbage collection to finalize the object.
Collect();
// Wait for the GC's Finalize thread to finish.
WaitForPendingFinalizers();
}
//150% slower than doing nothing
static private void TestDispose(int count)
{
DisposableObject []obj = new DisposableObject[count];
for(int i=0;i<count;i++)
obj[i]=new DisposableObject();
// Do some work with the object here ...

// Release the object.
for(int i=0;i<count;i++)
obj[i].Dispose();
obj = null;

// Forcing garbage collection to finalize the object.
Collect();
// Wait for the GC's Finalize thread to finish.
WaitForPendingFinalizers();
}
//best solution
static private voide LetDotnetCleanup(int count)
{

// Start performance timing
t.Start();
int count=int.Parse(args[0]);
DisposableObject []obj = new DisposableObject[count];
for(int i=0;i<count;i++)
obj[i]=new DisposableObject();

// Do some work with the object here ...

// Release the object.
obj = null;

t.Stop();
// Stop performance timing
}

6. Locks //ReaderWriterLock is 20 times slower than lock

ReaderWriterLock rwl = new ReaderWriterLock();
int m_Value = 0;

public int ReadUsingReadWriteLock(Int32 threadNum)
{
int Value = 0;

Console.WriteLine("Start Resource reading using ReadWriteLock (Thread={0})", threadNum);

t.Start();
rwl.AcquireReaderLock(Timeout.Infinite);

try
{
Value = m_Value;
}
finally
{
rwl.ReleaseReaderLock();
}
t.Stop();

Console.WriteLine("Stop Resource reading using ReadWriteLock (Thread={0})", threadNum);
Display.Show(1, " Elapsed time: " + t.ElapsedTime.ToString() + " ms \n", -1);

return Value;
}
public int ReadUsingLock(Int32 threadNum)
{
int Value = 0;

Console.WriteLine("Start Resource reading using lock(this) (Thread={0})", threadNum);

t.Start();
lock(this)
{
Value = m_Value;
}
t.Stop();

Console.WriteLine("Stop Resource reading using lock(this) (Thread={0})", threadNum);
Display.Show(1, " Elapsed time: " + t.ElapsedTime.ToString() + " ms \n", -1);

return Value;
}

7. Stack and Heap

N structures are Log(N) faster to allocate than N classes
class ClassObject
{
public int x;
}

struct StructObject
{
public int x;
}
//alloc structs
tAllocation.Start();
for (i = 0; i < repeat; i++) // repeat to get more acurate timing
s = new StructObject();
tAllocation.Stop();

//alloc objects
for (i = 0; i < repeat; i++) // repeat to get more acurate timing
c = new ClassObject();
  Reference http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/highperfmanagedapps.asp