• Net中的并发锁


    object _lock

    锁的概念,这里不做详细阐述。先从最经典的应用场景来说,单例模式在不考虑静态构造函数实现的方式下,用锁实现是必须的。比如:

    public class Singleton
    {
        private static Singleton _Singleton = null;
        private static object Singleton_Lock = new object();
        public static Singleton CreateInstance()
        {
            if (_Singleton == null)  
            {
                lock (Singleton_Lock)
                { 
                    if (_Singleton == null)
                    { 
                        _Singleton = new Singleton();
                    }
                }
            }
            return _Singleton;
        }
    }
    

    这里我们注意到

    static object Singleton_Lock = new object()

    这里的lock,其实是一个语法糖,具体定义就不多说,也不是本文的重点。简单说一下lock的注意事项
    1. lock的对象必须是引用类型(string类型比较特殊,会被CLR‘暂留’,所以也不行)
    2. lock推荐使用静态、私有、只读的对象。
    3. 对于2中的只读,是需要保证在lock外无法修改。也补充了第一点中string类型不行的原因。
    4. lock(this),如果无法保证外部及其他线程是否会访问,最好不要这样。因为可能会发生死锁。

    综上,lock(readonly static referenceTypes)是最优雅的使用方式。

    Net3.5中的ReaderWriterLockSlim

    ReaderWriterLockSlim支持三种锁定模式
    1. Read
    2. Write
    3. UpgradeableRead
    这三种锁定模式所对应的方法分别是:
    1. EnterReadLock
    2. EnterWriteLock
    3. EnterUpgradeableReadLock

    其中,Read模式是共享锁定模式,任意线程都可以在此模式下同时获得锁。
    Write模式是互斥模式,任意数量线程只允许一个线程进入该锁。

    其实这篇博文的目的,就是为了测试传统Object_lock 和ReaderWriteLockSlim的性能差异。废话不多,实现上使用了赵姐夫的CodeTimer

    测试代码如下:

    public class MemoryCache<TKey, TValue>
    {
        private ConcurrentDictionary<TKey, TValue> _dicCache = new ConcurrentDictionary<TKey, TValue>();
    
        private Dictionary<TKey, Lazy<TValue>> _dicLazyValue = new Dictionary<TKey, Lazy<TValue>>();
    
        private ReaderWriterLockSlim _cacheLock = new ReaderWriterLockSlim();
    
        private object _locker = new object();
    
        public TValue GetValueByObjectLocker(TKey key, Lazy<TValue> value)
        {
            if (!_dicLazyValue.ContainsKey(key))
            {
                lock (_locker)
                {
                    if (!_dicLazyValue.ContainsKey(key))
                    {
                        _dicLazyValue.Add(key, value);
                    }
                }
            }
            if (_dicCache == null)
            {
                lock (_locker)
                {
                    if (_dicCache == null)
                    {
                        _dicCache = new ConcurrentDictionary<TKey, TValue>();
                    }
                }
            }
            return _dicCache.GetOrAdd(key, _dicLazyValue[key].Value);
        }
    
    
        public TValue GetValueByLockSlim(TKey key, Lazy<TValue> value)
        {
            if (!_dicLazyValue.ContainsKey(key))
            {
                try
                {
                    _cacheLock.EnterWriteLock();
                    if (!_dicLazyValue.ContainsKey(key))
                    {
                        _dicLazyValue.Add(key, value);
                    }
                }
                finally
                {
                    _cacheLock.ExitWriteLock();
                }
            }
            if (_dicCache == null)
            {
                try
                {
                    _cacheLock.EnterUpgradeableReadLock();
                    if (_dicCache == null)
                    {
                        _dicCache = new ConcurrentDictionary<TKey, TValue>();
                    }
                }
                finally
                {
                    _cacheLock.ExitUpgradeableReadLock();
                }
            }
            return _dicCache.GetOrAdd(key, _dicLazyValue[key].Value);
        }
    }
    

    使用控制台应用程序

    static void Main(string[] args)
    {
        MemoryCache<string, string> _memoryCache = new MemoryCache<string, string>();
        CodeTimer.Initialize();
        CodeTimer.Time("object lock", 1000, () =>
        {
            var lazyStr = new Lazy<string>(() => Thread.CurrentThread.ManagedThreadId.ToString());
            _memoryCache.GetValueByObjectLocker("123", lazyStr);
        });
    
        CodeTimer.Time("LockSlim", 1000, () =>
        {
            var lazyStr = new Lazy<string>(() => Thread.CurrentThread.ManagedThreadId.ToString());
            _memoryCache.GetValueByLockSlim("456", lazyStr);
        });
        System.Console.WriteLine("123");
        System.Console.ReadLine();
    }
    

    结果:

    object lock
        Time Elapsed:   7ms
        CPU Cycles:     6,414,332
        Gen 0:          0
        Gen 1:          0
        Gen 2:          0
    
    LockSlim
        Time Elapsed:   1ms
        CPU Cycles:     3,182,178
        Gen 0:          0
        Gen 1:          0
        Gen 2:          0
    

    综上,当下次有使用'锁'的时候,请优先考虑ReaderWriterLockSlim以获取更高的性能和更低的CPU Cycles.

    鸟文名:YamatAmain
    地 址:http://www.cnblogs.com/YamatAmain/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    <强化学习>无模型下计算给定策略对应的价值函数,Model free Prediction,评估一个给定策略的表现
    <强化学习>马尔可夫决策过程MDP
    <组合数学>排列组合(2)/可重组合,不相邻组合,SJT算法
    <组合数学>排列组合(1)/格路模型,范德蒙德恒等式
    <组合数学>计数/加减乘除计数/加法法则/乘法法则/减法法则
    <组合数学>开门帖
    <组合数学>幻方
    Windows装机必备
    利用Jmeter操作MySQL数据库
    利用Jenkins插件实现多个job并行后再触发job
  • 原文地址:https://www.cnblogs.com/YamatAmain/p/11589256.html
Copyright © 2020-2023  润新知