Здравствуйте, mihhon, Вы писали:
D>>Цифирь итоговая от запуска к запуску может влёгкую на порядок различаться.
M>не различалась
Значит Вы что-то делаете не так
![](/Forum/Images/smirk.gif)
Например, пускаете вовсе не тот код, что опубликовали на форуме; в Debug сборке, а не в Release; и т.п.
Я вот прямо сейчас запустил, ради прикола:
TestReaderWriterMultiTime: timer 5000ms, readersCount 50, writers 1, reads 18486018, writes 5084, readLock 270.474690655392ns, writeLock 983477.576711251ns
TestReaderWriterMultiTime: timer 5000ms, readersCount 50, writers 1, reads 826139, writes 1071, readLock 6052.25028717928ns, writeLock 4668534.08029879ns
M>ThreadPool стартует новые threads, если количество задач в очереди не меняется в течение 0,5секунды, тесты по 5секунд, т.е. к концу теста 11-12 threads
Да нипричём тут количество потоков. Просто в Вашем "тесте" lock'а блокировки практически никогда не возникают. Происходит это бо шаг Вашего цикла нагрузки почти в точности равен кванту — загадочный метод MakeTemporization() обеспечивает это явным образом. Посему когда следующий поток отправляется на исполнение — lock уже свободен.
D>>Как там автор нулевую загрузку увидел — не понимаю. Она — после "разогрева" ThreadPool'а — тоже должна быть около 100%. Разве что у автора нетбук
M>не знаю, посмотрю на большем отрезке времени
Вы лучше железо озвучьте, для начала.
vf>Смотри показатели для ReaderWriterLock для 11 потоков значительно улучшаются. 51 поток это неэфективно для двухядерного процессора, с гипертриденгом, ИМХО, как раз 4-6 ну может 8 потоков и должно работать для максимальной отдачи.
камень в огород FastResourceLock: на 2 х Хeon L5520 — hp proliant dl360 g6, на разогретом ThreadPool
int threadNum = writersCount + readersCount;
ThreadPool.SetMinThreads(threadNum, threadNum);
ThreadPool.SetMaxThreads(threadNum, threadNum);
, на 50 читающих threads какая-то бага , блокируются все читатели
![](/Forum/Images/wink.gif)
хороший такой троянский конь в production может получиться
D:\homeware\tmp>test 5000 15 1
TestLockMultiTime: timer 5000ms, readersCount 1, writersCount 15, reads 1607035, writes 603576, readLock 3111.31991524765ns, writeLock 8283.9609262131ns
TestLockMultiTime: timer 5000ms, readersCount 1, writersCount 15, reads 1594988, writes 608307, readLock 3134.81982309585ns, writeLock 8219.53388667235ns
TestLockMultiTime: timer 5000ms, readersCount 1, writersCount 15, reads 1590231, writes 602751, readLock 3144.19728957617ns, writeLock 8295.29938565013ns
TestReaderWriterMultiTime: timer 5000ms, readersCount 1, writersCount 15, reads 448730, writes 371055, readLock 11142.5578855882ns, writeLock 13475.0912937435ns
TestReaderWriterMultiTime: timer 5000ms, readersCount 1, writersCount 15, reads 269034, writes 375105, readLock 18585.0115598772ns, writeLock 13329.6010450407ns
TestFastResourceLockMultiTime: timer 5000ms, readersCount 1, writersCount 15, reads 1104259, writes 1005134, readLock 4527.92324988974ns, writeLock 4974.46111662724ns
TestFastResourceLockMultiTime: timer 5000ms, readersCount 1, writersCount 15, reads 1146701, writes 994956, readLock 4360.3345597501ns, writeLock 5025.34785457849ns
D:\homeware\tmp>test 5000 7 1
TestLockMultiTime: timer 5000ms, readersCount 1, writersCount 7, reads 2073003, writes 287957, readLock 2411.95984762202ns, writeLock 17363.7036085249ns
TestLockMultiTime: timer 5000ms, readersCount 1, writersCount 7, reads 2147753, writes 295181, readLock 2328.01444113918ns, writeLock 16938.7596085114ns
TestLockMultiTime: timer 5000ms, readersCount 1, writersCount 7, reads 2135838, writes 295643, readLock 2341.00151790538ns, writeLock 16912.2894842766ns
TestReaderWriterMultiTime: timer 5000ms, readersCount 1, writersCount 7, reads 1050802, writes 243831, readLock 4758.2703496948ns, writeLock 20506.0062092187ns
TestReaderWriterMultiTime: timer 5000ms, readersCount 1, writersCount 7, reads 959999, writes 244101, readLock 5208.33875868621ns, writeLock 20483.3245255038ns
TestFastResourceLockMultiTime: timer 5000ms, readersCount 1, writersCount 7, reads 1597978, writes 752734, readLock 3128.95421589033ns, writeLock 6642.45271237914ns
TestFastResourceLockMultiTime: timer 5000ms, readersCount 1, writersCount 7, reads 1798527, writes 780656, readLock 2780.05278764233ns, writeLock 6404.86975056875ns
D:\homeware\tmp>test 5000 50 1
TestLockMultiTime: timer 5000ms, readersCount 1, writersCount 50, reads 275440, writes 1628526, readLock 18152.7737438281ns, writeLock 3070.26108272143ns
TestLockMultiTime: timer 5000ms, readersCount 1, writersCount 50, reads 238900, writes 1435977, readLock 20929.2591042277ns, writeLock 3481.94991981069ns
TestLockMultiTime: timer 5000ms, readersCount 1, writersCount 50, reads 239186, writes 1536342, readLock 20904.2335253736ns, writeLock 3254.48370219652ns
TestReaderWriterMultiTime: timer 5000ms, readersCount 1, writersCount 50, reads 88512, writes 488839, readLock 56489.5155459147ns, writeLock 10228.3164804772ns
TestReaderWriterMultiTime: timer 5000ms, readersCount 1, writersCount 50, reads 136403, writes 426882, readLock 36656.0852767168ns, writeLock 11712.8386767303ns
TestFastResourceLockMultiTime: timer 5000ms, readersCount 1, writersCount 50, reads 1, writes 834111, readLock 5000000000ns, writeLock 5994.40602030185ns
TestFastResourceLockMultiTime: timer 5000ms, readersCount 1, writersCount 50, reads 1, writes 830261, readLock 5000000000ns, writeLock 6022.20265675492ns
D>Вы лучше железо озвучьте, для начала.
я поправил тест, ThreadPool сразу содержит требуемое количство threads, и размер пула не меняется
MakeTemporization — это метод, который должен позволить моделизировать "реальную" нагрузку приложения: чтоб количество записей было в XXX раз меньше чтений , я не знаю как лучше его реализовать : Thread.Sleep(1) с учётом точности таймера не самое лучшее решение. я поправил его : убрал Thread.Sleep(0).
в итоге: если смотреть на цифры, я не вижу никакой выгоды от ReaderWriterLockSlim: он всё время поразывает худший результат, чем lock, а FastResourceLock , похоже с багами
начальный вопрос: когда же выгоднее использовать ReaderWriterLockSlim, сколько процессоров и какое соотношение чтений/записей ?
2x Xeon 4cores = 8 cores
10000 reads for 1 write:
D:\homeware\tmp>test 5000 1 7
TestLockMultiTime: timer 5000ms, readersCount 7, writersCount 1, reads 9108150, writes 221401
TestLockMultiTime: timer 5000ms, readersCount 7, writersCount 1, reads 8521472, writes 210999
TestLockMultiTime: timer 5000ms, readersCount 7, writersCount 1, reads 9302736, writes 215200
TestReaderWriterMultiTime: timer 5000ms, readersCount 7, writersCount 1, reads 8278425, writes 28215
TestReaderWriterMultiTime: timer 5000ms, readersCount 7, writersCount 1, reads 7152855, writes 36786
TestFastResourceLockMultiTime: timer 5000ms, readersCount 7, writersCount 1, reads 16821177, writes 59111
TestFastResourceLockMultiTime: timer 5000ms, readersCount 7, writersCount 1, reads 16514123, writes 61588
D:\homeware\tmp>test 5000 1 15
TestLockMultiTime: timer 5000ms, readersCount 15, writersCount 1, reads 8846441, writes 167201
TestLockMultiTime: timer 5000ms, readersCount 15, writersCount 1, reads 9069098, writes 175200
TestLockMultiTime: timer 5000ms, readersCount 15, writersCount 1, reads 9120507, writes 170600
TestReaderWriterMultiTime: timer 5000ms, readersCount 15, writersCount 1, reads 4633077, writes 12402
TestReaderWriterMultiTime: timer 5000ms, readersCount 15, writersCount 1, reads 4524697, writes 15409
TestFastResourceLockMultiTime: timer 5000ms, readersCount 15, writersCount 1, reads 14846097, writes 17651
TestFastResourceLockMultiTime: timer 5000ms, readersCount 15, writersCount 1, reads 14639979, writes 17052
D:\homeware\tmp>test 5000 1 50
TestLockMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 9050320, writes 30625
TestLockMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 9046398, writes 28523
TestLockMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 8908890, writes 30653
TestReaderWriterMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 3681543, writes 821
TestReaderWriterMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 3520756, writes 356
TestFastResourceLockMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 12145279, writes 4023
TestFastResourceLockMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 15444010, writes 2111
public class LockTestProgram
{
[DllImport("kernel32.dll")]
static extern bool SwitchToThread();
static IDictionary<string, string> dictionary = new Dictionary<string, string>();
public static void Main(string[] args)
{
Thread.CurrentThread.Name = "Main";
if (args.Length != 3)
{
System.Console.WriteLine("usage: progName time(millis) writersCount readersCount");
return;
}
for (int i = 0; i < 1000000; i++)
{
dictionary[i.ToString()] = i.ToString();
}
int millis = int.Parse(args[0]);
int writersCount = int.Parse(args[1]);
int readersCount = int.Parse(args[2]);
int threadNum = writersCount + readersCount;
ThreadPool.SetMinThreads(threadNum, threadNum);
ThreadPool.SetMaxThreads(threadNum, threadNum);
// warm the pool
TestLockMultiTime(millis, writersCount, readersCount);
Thread.Sleep(200);
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);
TestFastResourceLockMultiTime(millis, writersCount, readersCount);
Thread.Sleep(200);
TestFastResourceLockMultiTime(millis, writersCount, readersCount);
// 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 empty loop estimation
private static void TestEmptyLoop(int load)
{
int a = 0;
Stopwatch start = Stopwatch.StartNew();
for (int i = 0; i < load; i++)
{
a++;
}
long elapsed = start.ElapsedMilliseconds;
System.Console.WriteLine(
string.Format(
"TestEmptyLoop: load {0}, elapsed millis {1}, wo locking {2}ns",
load, elapsed, ((double)elapsed) / load * 1000000));
}
#endregion
#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;
string b;
ThreadStart writer = delegate()
{
while (flag)
{
lock (obj)
{
long localW = Interlocked.Increment(ref writes);
localW %= dictionary.Count;
dictionary[localW.ToString()] = localW.ToString();
}
MakeTemporization(false);
}
};
ThreadStart reader = delegate()
{
while (flag)
{
lock (obj)
{
long localW = Interlocked.Increment(ref reads);
localW %= dictionary.Count;
b = dictionary[localW.ToString()];
}
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}",
millis, readersCount, writersCount, reads, writes));
}
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;
string b;
ThreadStart writer = delegate()
{
while (flag)
{
LOCK.EnterWriteLock();
try
{
long localW = Interlocked.Increment(ref writes);
localW %= dictionary.Count;
dictionary[localW.ToString()] = localW.ToString();
}
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.ToString()];
}
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}",
millis, readersCount, writersCount, reads, writes));
}
private static void TestFastResourceLockMultiTime(int millis, int writersCount, int readersCount)
{
long reads = 0;
long writes = 0;
FastResourceLock LOCK = new FastResourceLock();
bool flag = true;
string b;
ThreadStart writer = delegate()
{
while (flag)
{
LOCK.AcquireExclusive();
try
{
long localW = Interlocked.Increment(ref writes);
localW %= dictionary.Count;
dictionary[localW.ToString()] = localW.ToString();
}
finally
{
LOCK.ReleaseExclusive();
}
MakeTemporization(false);
}
};
ThreadStart reader = delegate()
{
while (flag)
{
LOCK.AcquireShared();
try
{
long localW = Interlocked.Increment(ref reads);
localW %= dictionary.Count;
b = dictionary[localW.ToString()];
}
finally
{
LOCK.ReleaseShared();
}
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(
"TestFastResourceLockMultiTime: timer {0}ms, readersCount {1}, writersCount {2}, reads {3}, writes {4}",
millis, readersCount, writersCount, reads, writes));
}
private static int sleepReadCounter;
private static int sleepWriteCounter;
private static void MakeTemporization(bool read)
{
// 1- implementation 1: write to console
// System.Console.WriteLine(" ");
// 2- implementation 2: sleep
int step = read ? 2000000 : 200;
int localSleepCounter = read
? Interlocked.Increment(ref sleepReadCounter)
: Interlocked.Increment(ref sleepWriteCounter);
if (localSleepCounter % step == 0)
{
Thread.Sleep(1);
}
else
{
//Thread.Sleep(0);
//SwitchToThread();
}
// 3- implementation: switch the thread
// SwitchToThread();
}
#endregion
#region multithreaded with fixed number of interations
private static void TestLockMulti(int load, int writersCount, int readersCount)
{
int a = 0;
int b = 0;
object obj = new object();
ThreadStart writer = delegate()
{
for (int i = 0; i < load; i++)
{
lock (obj)
{
a++;
}
}
};
ThreadStart reader = delegate()
{
for (int i = 0; i < load; i++)
{
lock (obj)
{
b = a;
}
}
};
Stopwatch start = Stopwatch.StartNew();
// start threads
IAsyncResult[] writerResults = StartThreads(writersCount, writer);
IAsyncResult[] readerResults = StartThreads(readersCount, reader);
// wait for the execution
WaitThreads(writer, writerResults);
WaitThreads(reader, readerResults);
long elapsed = start.ElapsedMilliseconds;
System.Console.WriteLine(
string.Format(
"TestLockMulti: load {0}, readersCount {1}, writersCount {2}, elapsed millis {3}, 1 lock takes {4}ns",
load, readersCount, writersCount, elapsed, ((double)elapsed) / load * 1000000));
}
private static void TestReaderWriterMulti(int load, int writersCount, int readersCount)
{
int a = 0;
int b = 0;
ReaderWriterLockSlim LOCK = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
ThreadStart writer = delegate()
{
for (int i = 0; i < load; i++)
{
LOCK.EnterWriteLock();
try
{
a++;
}
finally
{
LOCK.ExitWriteLock();
}
}
};
ThreadStart reader = delegate()
{
for (int i = 0; i < load; i++)
{
LOCK.EnterReadLock();
try
{
b = a;
}
finally
{
LOCK.ExitReadLock();
}
}
};
Stopwatch start = Stopwatch.StartNew();
// start threads
IAsyncResult[] writerResults = StartThreads(writersCount, writer);
IAsyncResult[] readerResults = StartThreads(readersCount, reader);
// wait for the execution
WaitThreads(writer, writerResults);
WaitThreads(reader, readerResults);
long elapsed = start.ElapsedMilliseconds;
System.Console.WriteLine(
string.Format(
"TestReaderWriterMulti: load {0}, readersCount {1}, writersCount {2}, elapsed millis {3}, 1 lock takes {4}ns",
load, readersCount, writersCount, elapsed, ((double)elapsed) / load * 1000000));
}
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]);
}
}
}