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]);
            }
        }
    }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.