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