Re[8]: lock ws ReaderWriterLockSlim: интерес?
От: drol  
Дата: 23.01.11 13:14
Оценка: 4 (1)
Здравствуйте, vf, Вы писали:

vf>Смотри показатели для ReaderWriterLock для 11 потоков значительно улучшаются. 51 поток это неэфективно для двухядерного процессора, с гипертриденгом, ИМХО, как раз 4-6 ну может 8 потоков и должно работать для максимальной отдачи.


Уже третий день угораю над топиком Даже Sinclair повёлся — жуть

Какой ещё 51 поток ??? Там 51 задача во ThreadPool'е. Автор-то дёргает BeginInvoke() у делегата А так как ядер всего 2, и блокируемая операция занимает меньше кванта, то реальной одновременности практически нет. Цифирь итоговая от запуска к запуску может влёгкую на порядок различаться.

M>>кроме того TestReaderWriterMultiTime и TestFastResourceLockMultiTime кушают 100% процессора на 50 threads, lock — около нуля


vf>Ну понятно, что лок запихнул все потоки в очередь, и достает по одному.


В том и дело, что нет там никакой очереди. lock успевает отработать за квант, а ядер всего два, и ThreadPool не стартует worker'ов больше чем ядер. В итоге блокировок практически не бывает. Как там автор нулевую загрузку увидел — не понимаю. Она — после "разогрева" ThreadPool'а — тоже должна быть около 100%. Разве что у автора нетбук
Re[3]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 22.01.11 09:34
Оценка: -1
S>>А можно для тупых объяснить, каким образом вы при помощи lock разрешите одновременный доступ на чтение?
S>>Весь смысл ReaderWriterLock в том, чтобы 1000 читателей не выстраивались в очередь, а читали одновременно.
А>тупой может написать кусок кода (примеры экзотического программинга, типа распечатки на принтер энциклопедии из залоченной секции, не берём, реалистичный пример — запись/чтение в Dictionary в залоченной секции), который показывает, что ReaderWriterLockSlim выгоднее lock и закопипастить его сюда?

пример в студию! это был я
Re[9]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 23.01.11 15:25
Оценка: -1
D>Какой ещё 51 поток ??? Там 51 задача во ThreadPool'е. Автор-то дёргает BeginInvoke() у делегата А так как ядер всего 2, и блокируемая операция занимает меньше кванта, то реальной одновременности практически нет. Цифирь итоговая от запуска к запуску может влёгкую на порядок различаться.

D>В том и дело, что нет там никакой очереди. lock успевает отработать за квант, а ядер всего два, и ThreadPool не стартует worker'ов больше чем ядер. В итоге блокировок практически не бывает. Как там автор нулевую загрузку увидел — не понимаю. Она — после "разогрева" ThreadPool'а — тоже должна быть около 100%. Разве что у автора нетбук


завтра посмотрю, что будет, если через ThreadPool, с выставлением MinThreads
lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 21.01.11 14:49
Оценка:
не могу никак придумать пример, на котором был бы выигрыш от 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]);
            }
        }
    }
Re: lock ws ReaderWriterLockSlim: интерес?
От: vf  
Дата: 21.01.11 15:47
Оценка:
Здравствуйте, mihhon, Вы писали:

ИМХО замеры ошибочны, сильно не вникал но вот такие вопросы/предположения:

1. Не понятно почему время записи с локом намного больше времени чтения?! Кривой способ измерения...

2. По записи, проигрыш в разы связан со способом измерений, ведь чтобы readwritelockslim получил экслюзивный доступ он наверное дожидается пока читатели закончат читать. Думаю правильнее мерять скорость лока без читателей.

3. По чтению, выйгрыш сильно зависит от времени нахождения в залоченом участке, dictonary слишком быстрый получился, HashCode быстро вычисляется из int и это нивелирует преимущество.

Вообще к производительности readwritelockslim у многих вопросы, вот хорошая статья, там более корректные замеры присутствуют, и решение предлогается.
Re[2]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 21.01.11 15:58
Оценка:
vf>1. Не понятно почему время записи с локом намного больше времени чтения?! Кривой способ измерения...
время в этих замерах несущественно (откопипастено из других тестов), главное — количество чтений/записи

vf>2. По записи, проигрыш в разы связан со способом измерений, ведь чтобы readwritelockslim получил экслюзивный доступ он наверное дожидается пока читатели закончат читать. Думаю правильнее мерять скорость лока без читателей.

1. не имеет смысла лочить, если есть только ридеры
2. readwritelockslim — для случаев когра запись делается раз в день ?

vf>3. По чтению, выйгрыш сильно зависит от времени нахождения в залоченом участке, dictonary слишком быстрый получился, HashCode быстро вычисляется из int и это нивелирует преимущество.

ну это как руки мыть перед едой — не запихивать в залоченные секции кучу кода

vf>Вообще к производительности readwritelockslim у многих вопросы, вот хорошая статья, там более корректные замеры присутствуют, и решение предлогается.

сейчас посмотрим
Re[2]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 21.01.11 16:21
Оценка:
vf>2. По записи, проигрыш в разы связан со способом измерений, ведь чтобы readwritelockslim получил экслюзивный доступ он наверное дожидается пока читатели закончат читать. Думаю правильнее мерять скорость лока без читателей.
неправильно прочитал
какой смысл мерить, если есть только writers? в этом случае не имеет смысла использовать readwritelockslim?
Re[3]: lock ws ReaderWriterLockSlim: интерес?
От: vf  
Дата: 21.01.11 16:38
Оценка:
Здравствуйте, mihhon, Вы писали:

vf>>2. По записи, проигрыш в разы связан со способом измерений, ведь чтобы readwritelockslim получил экслюзивный доступ он наверное дожидается пока читатели закончат читать. Думаю правильнее мерять скорость лока без читателей.


M>1. не имеет смысла лочить, если есть только ридеры


Я этого не предлогал. Я предложил сравнить время получения экслюзивного доступа когда нет читателей, со временем лока.

M>2. readwritelockslim — для случаев когра запись делается раз в день ?


Я ни разу не майкрософт Но думаю не все так однозначно... на мой взгляд тесты не корретны.

vf>>3. По чтению, выйгрыш сильно зависит от времени нахождения в залоченом участке, dictonary слишком быстрый получился, HashCode быстро вычисляется из int и это нивелирует преимущество.

M>ну это как руки мыть перед едой — не запихивать в залоченные секции кучу кода

Понятно, только я не об этом, ладно скажу по другому, конкретно в этом синтетическом тесте реализован вариант в котором readwritelockslim будет показывать худший результат, чем в среднем в реальных приложениях.
Re[3]: lock ws ReaderWriterLockSlim: интерес?
От: vf  
Дата: 21.01.11 16:52
Оценка:
Здравствуйте, mihhon, Вы писали:

vf>>2. По записи, проигрыш в разы связан со способом измерений, ведь чтобы readwritelockslim получил экслюзивный доступ он наверное дожидается пока читатели закончат читать. Думаю правильнее мерять скорость лока без читателей.

M>неправильно прочитал
M>какой смысл мерить, если есть только writers? в этом случае не имеет смысла использовать readwritelockslim?

Я не знаю как он реализован, но писателю как минимум придеться ждать пока закончат читатели, которые начали читать до записи. А может даже хуже...

А если замерить сколько времени нужно на получения эксклюзивного доступа без "помех", тогда можно сказать насколько он медленее обычного лока — ведь и то и то эксклюзивный доступ. Но у первого дополнительные накладные расходы на сложность. А так не понятно что ты замерил, ведь суммарное число операции у readwritelockslim значительно больше, можно сказать что он победил просто у ридеров "приоритет" (условно, из реализации алгоритма и условий тестов) выше.
Re[4]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 21.01.11 17:08
Оценка:
vf>Я этого не предлогал. Я предложил сравнить время получения экслюзивного доступа когда нет читателей, со временем лока.
readwritelockslim в 2 раза медленнее примерно, и в моно-thread (если просто оверхэд от добавления в код мерить) и в мульти-thread (1 thread пишет, другой читает, время нахождения в залоченом участке 0 — не очень хорошо, конечно ...)

M>>2. readwritelockslim — для случаев когра запись делается раз в день ?


vf>Я ни разу не майкрософт Но думаю не все так однозначно... на мой взгляд тесты не корретны.

одна запись на десять/сто/тысячу чтений, при одном thread, который пишет на 5/10/50/100 читающих: вполне хороший разброс для тестов, во всех трёх случах нет выигрыша (чуть лучше чтение, но запись хуже существенно)

vf>>>3. По чтению, выйгрыш сильно зависит от времени нахождения в залоченом участке, dictonary слишком быстрый получился, HashCode быстро вычисляется из int и это нивелирует преимущество.

M>>ну это как руки мыть перед едой — не запихивать в залоченные секции кучу кода

vf>Понятно, только я не об этом, ладно скажу по другому, конкретно в этом синтетическом тесте реализован вариант в котором readwritelockslim будет показывать худший результат, чем в среднем в реальных приложениях.

сделал тот же тест, но ключ в dictionary — string, то же самое соотношение результатов
Re[4]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 21.01.11 17:17
Оценка:
vf>Я не знаю как он реализован, но писателю как минимум придеться ждать пока закончат читатели, которые начали читать до записи. А может даже хуже...

vf>А если замерить сколько времени нужно на получения эксклюзивного доступа без "помех"

в 2 раза хуже

vf>А так не понятно что ты замерил, ведь суммарное число операции у readwritelockslim значительно больше, можно сказать что он победил просто у ридеров "приоритет" (условно, из реализации алгоритма и условий тестов) выше.

я сравнил lock и ReaderWriterLockSlim, стало инересно, имеет ли смысл ReaderWriterLockSlim использовать, в сценарии, который приближен к программке, которую пишу: 1 thread пишет, 4-8 читают, на 1 запись приходится 10-40 чтений. и посмотрел результаты тестов с разным набором параметров

и никакой выгоды от ReaderWriterLockSlim нет в таком сценарии. а код менее читабельный и можно перепутать/накопипастить EnterWriteLock->ExitReadLock (было такое), (про конструкцию с using написать оболочку вокруг ReaderWriterLockSlim знаю)
Re[2]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 21.01.11 17:20
Оценка:
vf>Вообще к производительности readwritelockslim у многих вопросы, вот хорошая статья, там более корректные замеры присутствуют, и решение предлогается.
основной вывод из статьи: пишите грамотный код — минимизируйте залоченные секции, lock — достаточно и наиболее быстро
Re[5]: lock ws ReaderWriterLockSlim: интерес?
От: vf  
Дата: 21.01.11 17:39
Оценка:
Здравствуйте, mihhon, Вы писали:

vf>>А так не понятно что ты замерил, ведь суммарное число операции у readwritelockslim значительно больше, можно сказать что он победил просто у ридеров "приоритет" (условно, из реализации алгоритма и условий тестов) выше.

M>я сравнил lock и ReaderWriterLockSlim, стало инересно, имеет ли смысл ReaderWriterLockSlim использовать, в сценарии, который приближен к программке, которую пишу: 1 thread пишет, 4-8 читают, на 1 запись приходится 10-40 чтений. и посмотрел результаты тестов с разным набором параметров

А тестовое приложение какие результаты показывает для 4-8 читателей?
Попробуй туда FastResourceLock из статьи подставить, любопытно.

M>про конструкцию с using написать оболочку вокруг ReaderWriterLockSlim знаю


Не сталкивался здесь она? Если да, то создавать каждый раз объект — затратно.
Re[6]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 21.01.11 18:16
Оценка:
vf>А тестовое приложение какие результаты показывает для 4-8 читателей?
vf>Попробуй туда FastResourceLock из статьи подставить, любопытно.


TestLockMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 6630345, writes 59657, readLock 754.108572027549ns, writeLock 83812.4612367367ns
TestReaderWriterMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 8298059, writes 7583, readLock 602.550548266769ns, writeLock 659369.642621654ns
TestFastResourceLockMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 8927731, writes 14211, readLock 560.052716642112ns, writeLock 351840.123847724ns
TestReaderWriterMultiTime, TestFastResourceLockMultiTime - 100% of CPU !!!! with 50 readers

TestLockMultiTime: timer 5000ms, readersCount 10, writersCount 1, reads 5959031, writes 80969, readLock 839.062592559092ns, writeLock 61752.028554138ns
TestReaderWriterMultiTime: timer 5000ms, readersCount 10, writersCount 1, reads 6192030, writes 35970, readLock 807.489627795731ns, writeLock 139004.726160689ns
TestFastResourceLockMultiTime: timer 5000ms, readersCount 10, writersCount 1, reads 6318584, writes 77415, readLock 791.316535476936ns, writeLock 64586.9663501905ns

FastResourceLock делает в 2 раза больше записей чем ReaderWriterLockSlim, оба делают чуть больше чтений но проигрывают сильно в количестве записей lock-у

кроме того TestReaderWriterMultiTime и TestFastResourceLockMultiTime кушают 100% процессора на 50 threads, lock - около нуля



M>>про конструкцию с using написать оболочку вокруг ReaderWriterLockSlim знаю


vf>Не сталкивался здесь она? Если да, то создавать каждый раз объект — затратно.

da


source

    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)
        {
            

            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]);

            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 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}, 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;
            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}, readLock {5}ns, writeLock {6}ns",
                millis, readersCount, writersCount, reads, writes, ((double)millis) / reads * 1000000, ((double)millis) / writes * 1000000));
        }

        
        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}, 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();
        }
    }
Re[7]: lock ws ReaderWriterLockSlim: интерес?
От: vf  
Дата: 21.01.11 18:58
Оценка:
Здравствуйте, mihhon, Вы писали:


M>TestLockMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 6630345, writes 59657, readLock 754.108572027549ns, writeLock 83812.4612367367ns

M>TestReaderWriterMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 8298059, writes 7583, readLock 602.550548266769ns, writeLock 659369.642621654ns
M>TestFastResourceLockMultiTime: timer 5000ms, readersCount 50, writersCount 1, reads 8927731, writes 14211, readLock 560.052716642112ns, writeLock 351840.123847724ns
M>TestReaderWriterMultiTime, TestFastResourceLockMultiTime — 100% of CPU !!!! with 50 readers

M>TestLockMultiTime: timer 5000ms, readersCount 10, writersCount 1, reads 5959031, writes 80969, readLock 839.062592559092ns, writeLock 61752.028554138ns

M>TestReaderWriterMultiTime: timer 5000ms, readersCount 10, writersCount 1, reads 6192030, writes 35970, readLock 807.489627795731ns, writeLock 139004.726160689ns
M>TestFastResourceLockMultiTime: timer 5000ms, readersCount 10, writersCount 1, reads 6318584, writes 77415, readLock 791.316535476936ns, writeLock 64586.9663501905ns

M>FastResourceLock делает в 2 раза больше записей чем ReaderWriterLockSlim, оба делают чуть больше чтений но проигрывают сильно в количестве записей lock-у


Смотри показатели для ReaderWriterLock для 11 потоков значительно улучшаются. 51 поток это неэфективно для двухядерного процессора, с гипертриденгом, ИМХО, как раз 4-6 ну может 8 потоков и должно работать для максимальной отдачи.

Я думаю на 4 потоках ReaderWriterLockSlim покажет свою реальную область применения — процент чтений/записей при которых он выгоднее чем лок. Хотя меня расстраивает, что такая красивая идея не рвет в клочья лок во всех случаях.

Не совсем понял твой вывод по FastResourceLock, ведь он сделал на 300К больше чтений чем лок, по записи проиграл 4.5К но цифры там сопоставимы — я бы его признал победителем для 11 потоков.

M>кроме того TestReaderWriterMultiTime и TestFastResourceLockMultiTime кушают 100% процессора на 50 threads, lock — около нуля


Ну понятно, что лок запихнул все потоки в очередь, и достает по одному. Я понимаю что хочеться протестировать на запредельных для реального приложения параметрах, но 50 потоков это совсем другой случай — в действительности они же не будут работать паралельно...
Re: lock ws ReaderWriterLockSlim: интерес?
От: Sinclair Россия https://github.com/evilguest/
Дата: 22.01.11 05:30
Оценка:
Здравствуйте, mihhon, Вы писали:

M>не могу никак придумать пример, на котором был бы выигрыш от ReaderWriterLockSlim по сравнению с lock более существенный, чем в 2 раза при чтении (часто при существенном при проигрыше в записи), это нормально ? больше не получится?

M>при том оверхед от ReaderWriterLockSlim в 2 раза больше
А можно для тупых объяснить, каким образом вы при помощи lock разрешите одновременный доступ на чтение?
Весь смысл ReaderWriterLock в том, чтобы 1000 читателей не выстраивались в очередь, а читали одновременно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: lock ws ReaderWriterLockSlim: интерес?
От: vf  
Дата: 22.01.11 08:38
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А можно для тупых объяснить, каким образом вы при помощи lock разрешите одновременный доступ на чтение?

S>Весь смысл ReaderWriterLock в том, чтобы 1000 читателей не выстраивались в очередь, а читали одновременно.

Где взять 1000 читателей на десктопе?! Теория вопросов не вызывает — красиво, но я так понял автор ищет реальный общий случай для дот .нет приложений для которого можно сказать: "здесь нужно использовать ReaderWriterLockSlim"...
Dictonary хороший кандидат, на такую потокобезопасную обертку.
Re[2]: lock ws ReaderWriterLockSlim: интерес?
От: Аноним  
Дата: 22.01.11 09:32
Оценка:
S>А можно для тупых объяснить, каким образом вы при помощи lock разрешите одновременный доступ на чтение?
S>Весь смысл ReaderWriterLock в том, чтобы 1000 читателей не выстраивались в очередь, а читали одновременно.
тупой может написать кусок кода (примеры экзотического программинга, типа распечатки на принтер энциклопедии из залоченной секции, не берём, реалистичный пример — запись/чтение в Dictionary в залоченной секции), который показывает, что ReaderWriterLockSlim выгоднее lock и закопипастить его сюда?
Re[3]: lock ws ReaderWriterLockSlim: интерес?
От: Sinclair Россия https://github.com/evilguest/
Дата: 22.01.11 11:46
Оценка:
Здравствуйте, vf, Вы писали:

vf>Где взять 1000 читателей на десктопе?!

1. А почему сразу на десктопе?
2. Что будем делать через пять-десять лет, когда ядер будет больше, чем сейчас мегабайт?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: lock ws ReaderWriterLockSlim: интерес?
От: vf  
Дата: 22.01.11 12:09
Оценка:
Здравствуйте, Sinclair, Вы писали:

vf>>Где взять 1000 читателей на десктопе?!

S>1. А почему сразу на десктопе?

Потому что я считаю что большинство дот нет серверов — это "адвансед десктоп машина", и число ядер там отличается в разы, но никак не на 3 порядка, что ситуацию не меняет.

S>2. Что будем делать через пять-десять лет, когда ядер будет больше, чем сейчас мегабайт?


Я ждал этого аргумента Софт развивается тоже очень быстро, если "ядер будет больше, чем сейчас мегабайт" будет другое более адекватное решение. А вообще я голосую за лок-фри!
Re[9]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 23.01.11 15:42
Оценка:
D>Цифирь итоговая от запуска к запуску может влёгкую на порядок различаться.
не различалась

D>В том и дело, что нет там никакой очереди. lock успевает отработать за квант, а ядер всего два, и ThreadPool не стартует worker'ов больше чем ядер. В итоге блокировок практически не бывает.

ThreadPool стартует новые threads, если количество задач в очереди не меняется в течение 0,5секунды, тесты по 5секунд, т.е. к концу теста 11-12 threads

D>Как там автор нулевую загрузку увидел — не понимаю. Она — после "разогрева" ThreadPool'а — тоже должна быть около 100%. Разве что у автора нетбук

не знаю, посмотрю на большем отрезке времени
Re[10]: lock ws ReaderWriterLockSlim: интерес?
От: drol  
Дата: 23.01.11 16:48
Оценка:
Здравствуйте, mihhon, Вы писали:

D>>Цифирь итоговая от запуска к запуску может влёгкую на порядок различаться.

M>не различалась

Значит Вы что-то делаете не так Например, пускаете вовсе не тот код, что опубликовали на форуме; в 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>не знаю, посмотрю на большем отрезке времени

Вы лучше железо озвучьте, для начала.
Re[11]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 24.01.11 08:45
Оценка:
D>Вы лучше железо озвучьте, для начала.
Intel® Core™2 Duo Processor E8400
# of Cores 2
# of Threads 2

есть ещё такой, на нём 4 ядра
Intel® Xeon® Processor L5520
# of Cores 4
# of Threads 8
Re[11]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 24.01.11 08:51
Оценка:
D>Вы лучше железо озвучьте, для начала.
тот что xeon — hp proliant dl360 g6 , 2 процессора, task manager и device manager показывают 16 процессоров
Re[8]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 24.01.11 09:49
Оценка:
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 какая-то бага , блокируются все читатели хороший такой троянский конь в 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
Re[9]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 24.01.11 09:55
Оценка:
перепутал ридеров и райтеров, но бага есть всё равно
Re[11]: lock ws ReaderWriterLockSlim: интерес?
От: mihhon  
Дата: 24.01.11 11:01
Оценка:
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]);
            }
        }
    }
Re[12]: lock ws ReaderWriterLockSlim: интерес?
От: vf  
Дата: 24.01.11 12:59
Оценка:
Здравствуйте, mihhon, Вы писали:

M>FastResourceLock , похоже с багами


When that thread is done with the lock, it clears the L bit (so other threads can set it to acquire the lock). If the thread sees that there is an exclusive waiter (by looking at EW), it releases the semaphore once, waking up an exclusive waiter. If there are no exclusive waiters but there are shared waiters, it releases all of them at once (since they can all acquire the lock at the same time – that is the whole point of a reader-writer lock).


Там нет очереди... Это не баг, это особенность. Думаю при желании такое поведение можно легко изменить, хотя 50 писателей и 1 читатель не совсем та ситуации, а этот механизм без претензий на универсальность?!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.