I'm doing a very silly benchmark on the ReaderWriterLock with this code, where reading happens 4x more often than writting:
class Program
{
static void Main()
{
ISynchro[] test = { new Locked(), new RWLocked() };
Stopwatch sw = new Stopwatch();
foreach ( var isynchro in test )
{
sw.Reset();
sw.Start();
Thread w1 = new Thread( new ParameterizedThreadStart( WriteThread ) );
w1.Start( isynchro );
Thread w2 = new Thread( new ParameterizedThreadStart( WriteThread ) );
w2.Start( isynchro );
Thread r1 = new Thread( new ParameterizedThreadStart( ReadThread ) );
r1.Start( isynchro );
Thread r2 = new Thread( new ParameterizedThreadStart( ReadThread ) );
r2.Start( isynchro );
w1.Join();
w2.Join();
r1.Join();
r2.Join();
sw.Stop();
Console.WriteLine( isynchro.ToString() + ": " + sw.ElapsedMilliseconds.ToString() + "ms." );
}
Console.WriteLine( "End" );
Console.ReadKey( true );
}
static void ReadThread(Object o)
{
ISynchro synchro = (ISynchro)o;
for ( int i = 0; i < 500; i++ )
{
Int32? value = synchro.Get( i );
Thread.Sleep( 50 );
}
}
static void WriteThread( Object o )
{
ISynchro synchro = (ISynchro)o;
for ( int i = 0; i < 125; i++ )
{
synchro.Add( i );
Thread.Sleep( 200 );
}
}
}
interface ISynchro
{
void Add( Int32 value );
Int32? Get( Int32 index );
}
class Locked:List<Int32>, ISynchro
{
readonly Object locker = new object();
#region ISynchro Members
public new void Add( int value )
{
lock ( locker )
base.Add( value );
}
public int? Get( int index )
{
lock ( locker )
{
if ( this.Count <= index )
return null;
return this[ index ];
}
}
#endregion
public override string ToString()
{
return "Locked";
}
}
class RWLocked : List<Int32>, ISynchro
{
ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
#region ISynchro Members
public new void Add( int value )
{
try
{
locker.EnterWriteLock();
base.Add( value );
}
finally
{
locker.ExitWriteLock();
}
}
public int? Get( int index )
{
try
{
locker.EnterReadLock();
if ( this.Count <= index )
return null;
return this[ index ];
}
finally
{
locker.ExitReadLock();
}
}
#endregion
public override string ToString()
{
return "RW Locked";
}
}
But I get that both perform in more or less the same way:
Locked: 25003ms.
RW Locked: 25002ms.
End
Even making the read 20 times more often that writes, the performance is still (almost) the same.
Am I doing something wrong here?
Kind regards.
My own tests indicate that
ReaderWriterLockSlim
has about 5x the overhead as compared to a normallock
. That means for the RWLS to outperform a plain old lock the following conditions would generally be occurring.In most real applications these two conditions are not enough to overcome that additional overhead. In your code specifically, the locks are held for such a short period of time that the lock overhead will probably be the dominating factor. If you were to move those
Thread.Sleep
calls inside the lock then you would probably get a different result.Unless you have multicore hardware (or at least the same as your planned production environment) you won't get a realistic test here.
A more sensible test would be to extend the lifetime of your locked operations by putting a brief delay inside the lock. That way you should really be able to contrast the parallelism added using
ReaderWriterLockSlim
versus the serialization implied by basiclock()
.Currently, the time taken by your operations that are locked are lost in the noise generated by the Sleep calls that happen outside the locks. The total time in either case is mostly Sleep-related.
Are you sure your real-world app will have equal numbers of reads and writes?
ReaderWriterLockSlim
is really better for the case where you have many readers and relatively infrequent writers. 1 writer thread versus 3 reader threads should demonstrateReaderWriterLockSlim
benefits better, but in any case your test should match your expected real-world access pattern.I guess this is because of the sleeps you have in you reader and writer threads.
Your read thread has a 500tims 50ms sleep which is 25000 Most of the time it is sleeping
Check out this article: http://blogs.msdn.com/b/pedram/archive/2007/10/07/a-performance-comparison-of-readerwriterlockslim-with-readerwriterlock.aspx
Your sleeps are probably long enough that they make your locking/unlocking statistically insignificant.