не могу никак придумать пример, на котором был бы выигрыш от ReaderWriterLockSlim по сравнению с lock более существенный, чем в 2 раза при чтении (часто при существенном при проигрыше в записи), это нормально ? больше не получится?
при том оверхед от ReaderWriterLockSlim в 2 раза больше
примеры экзотического программинга, типа распечатки на принтер энциклопедии из залоченной секции, не берём, реалистичный пример — запись/чтение в Dictionary в залоченной секции
пример:
Tests.exe 5000 1 50 > console.log
TestLockMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 6308033, writes 189967, readLock 792.640114596737ns, writeLock 26320.3609047887ns
TestReaderWriterMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 11098834, writes 24919, readLock 450.497773009309ns, writeLock 200650.106344556ns
1 thread пишет, 50 threads читают, на 1 запись - 1000 чтений: за фиксированное время при ReaderWriterLockSlim делается в 2 раза больше чтений, но в 10 раз меньше записей ...
2х ядерный процессор, .net 3.5
public class LockTestProgram
{
[DllImport("kernel32.dll")]
static extern bool SwitchToThread();
static IDictionary<long, long> dictionary = new Dictionary<long, long>();
public static void Main(string[] args)
{
if (args.Length != 3)
{
System.Console.WriteLine("usage: progName time(millis) writersCount readersCount");
return;
}
for (int i = 0; i < 1000000; i++ )
{
dictionary[i] = i;
}
int millis = int.Parse(args[0]);
int writersCount = int.Parse(args[1]);
int readersCount = int.Parse(args[2]);
TestLockMultiTime(millis, writersCount, readersCount);
Thread.Sleep(200);
TestLockMultiTime(millis, writersCount, readersCount);
Thread.Sleep(200);
TestReaderWriterMultiTime(millis, writersCount, readersCount);
Thread.Sleep(200);
TestReaderWriterMultiTime(millis, writersCount, readersCount);
Thread.Sleep(200);
// multithreaded with fixed number of interations
// if (args.Length != 3)
// {
// System.Console.WriteLine("usage: progName load writersCount readersCount");
// return;
// }
//
// int load = int.Parse(args[0]);
// int writersCount = int.Parse(args[1]);
// int readersCount = int.Parse(args[2]);
//
// TestLockMulti(load, writersCount, readersCount);
// TestLockMulti(load, writersCount, readersCount);
// TestReaderWriterMulti(load, writersCount, readersCount);
// TestReaderWriterMulti(load, writersCount, readersCount);
// monothreaded
// TestEmptyLoop(load);
// TestEmptyLoop(load);
// TestLock(load);
// TestLock(load);
// TestReaderWriterLockSlim_Read(load);
// TestReaderWriterLockSlim_Read(load);
// TestReaderWriterLockSlim_Write(load);
// TestReaderWriterLockSlim_Write(load);
}
#region multithreaded during the fixed time
private static void TestLockMultiTime(int millis, int writersCount, int readersCount)
{
long reads = 0;
long writes = 0;
object obj = new object();
bool flag = true;
long b;
ThreadStart writer = delegate()
{
while (flag)
{
lock (obj)
{
long localW = Interlocked.Increment(ref writes);
localW %= dictionary.Count;
dictionary[localW] = localW;
}
MakeTemporization(false);
}
};
ThreadStart reader = delegate()
{
while (flag)
{
lock (obj)
{
long localW = Interlocked.Increment(ref reads);
localW %= dictionary.Count;
b = dictionary[localW];
}
MakeTemporization(true);
}
};
Stopwatch start = Stopwatch.StartNew();
// start threads
IAsyncResult[] writerResults = StartThreads(writersCount, writer);
IAsyncResult[] readerResults = StartThreads(readersCount, reader);
Thread.Sleep(millis);
flag = false;
// wait for the execution
WaitThreads(writer, writerResults);
WaitThreads(reader, readerResults);
long elapsed = start.ElapsedMilliseconds;
System.Console.WriteLine(
string.Format(
"TestLockMultiTime: timer {0}ms, readersCount {1}, writersCount {2}, reads {3}, writes {4}, readLock {5}ns, writeLock {6}ns",
millis, readersCount, writersCount, reads, writes, ((double)millis) / reads * 1000000, ((double)millis) / writes * 1000000));
}
private static void TestReaderWriterMultiTime(int millis, int writersCount, int readersCount)
{
long reads = 0;
long writes = 0;
ReaderWriterLockSlim LOCK = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
bool flag = true;
long b;
ThreadStart writer = delegate()
{
while (flag)
{
LOCK.EnterWriteLock();
try
{
long localW = Interlocked.Increment(ref writes);
localW %= dictionary.Count;
dictionary[localW] = localW;
}
finally
{
LOCK.ExitWriteLock();
}
MakeTemporization(false);
}
};
ThreadStart reader = delegate()
{
while (flag)
{
LOCK.EnterReadLock();
try
{
long localW = Interlocked.Increment(ref reads);
localW %= dictionary.Count;
b = dictionary[localW];
}
finally
{
LOCK.ExitReadLock();
}
MakeTemporization(true);
}
};
Stopwatch start = Stopwatch.StartNew();
// start threads
IAsyncResult[] writerResults = StartThreads(writersCount, writer);
IAsyncResult[] readerResults = StartThreads(readersCount, reader);
Thread.Sleep(millis);
flag = false;
// wait for the execution
WaitThreads(writer, writerResults);
WaitThreads(reader, readerResults);
long elapsed = start.ElapsedMilliseconds;
System.Console.WriteLine(
string.Format(
"TestReaderWriterMultiTime: timer {0}ms, readersCount {1}, writersCount {2}, reads {3}, writes {4}, readLock {5}ns, writeLock {6}ns",
millis, readersCount, writersCount, reads, writes, ((double)millis) / reads * 1000000, ((double)millis) / writes * 1000000));
}
private static int sleepCounter;
private static void MakeTemporization(bool read)
{
// 1- implementation 1: write to console
// System.Console.WriteLine(" ");
// 2- implementation 2: sleep
int step = read ? 2000 : 20;
int localSleepCounter = Interlocked.Increment(ref sleepCounter);
if (localSleepCounter % step == 0)
{
Thread.Sleep(1);
}
else
{
Thread.Sleep(0);
//SwitchToThread();
}
// 3- implementation: switch the thread
// SwitchToThread();
}
#endregion
private static IAsyncResult[] StartThreads(int count, ThreadStart threadStart)
{
IAsyncResult[] results = new IAsyncResult[count];
for (int i = 0; i < count; i++)
{
results[i] = threadStart.BeginInvoke(delegate(IAsyncResult ar) { }, null);
}
return results;
}
private static void WaitThreads(ThreadStart threadStart, IAsyncResult[] results)
{
for (int i = 0; i < results.Length; i++)
{
threadStart.EndInvoke(results[i]);
}
}
}