There are two types of asynchronous operations in .NET.
For I/O bound
await syntax should be used. TPL should not be used for this.
async methods does not spawns new thread to hand le I/O work asynchronously.
For CPU bound operations TPL should be used (
Task.Run). This spawns new thread. Performance testing should be done to check if overhead of new thread and context switching is not greater than actual work to be done.
- CPU bound should be done in thread pool (
- I/O bound should not
- UI thread should do minimal work (mostly update UI or react to user actions)
- extensive computations should be done on different thread (CPU bound).
- I/O waits should be awaited (less overhead since
ThreadPool have some overhead)
- if I/O task are awaited then it is easier to update UI with new data (only one thread is allowed to update UI – main one)
- informs GC that object does not need to be added to finalizer queue
- finalizer execution is not deterministic and objects can live for long time in queue – this is optimization technique
- to make sure that object disposes of any unamanaged resources even if
Dispose will be not called we need to implement finalizer
Basically finalizer execution time is not deterministic. We cannot predict when this will be called and till that time – object is existing and still taking memory space. Since we are controlling creation and disposal of those resources we can say to GC: ‘Do not worry about that! It already had been taken care of!’. So this way object will be destroyed sooner, leaving this space to be used by something else possibly.
The Dispose() method must call
Dispose(true) and should suppress finalization for performance.
Example implementation of
public class MyResource : IDisposable
public MyResource(IntPtr handle)
this.handle = handle;
public void Dispose()
protected virtual void Dispose(bool disposing)
handle = IntPtr.Zero;
disposed = true;
MyResource object have pointer which is unmanaged. This is why this class should implement
IDisposable interface. Implementation should be correct according to recommended pattern (see below for documentation).
There a re few points to highlight here:
IDisposable is meant to be used with
using is calling
IDisposable.Dispose method in the background
- This method should be public then
protected Dispose(bool) method is meant to be called from finalizer via GC
SuppressFinalize disables this object from finalization mechanism in GC to prevent finalization code to be executed second time (see here)
- Finalization is called from GC *only* if whoever is using this object will forget to use
using or otherwise fail to call
Dispose must be save to call multiple times (
Dispose(true) is meant to dispose also any other managed resources this implementation relies on
Dispose(false) is meant to be called from GC finalization mechanism. All managed resource are most likely already disposed so we cannot dispose them again