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: интерес?
От: mihhon  
Дата: 22.01.11 09:34
Оценка: -1
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[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[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
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.