Net中的併發鎖

object _lock

鎖的概念,這裏不作詳細闡述。先從最經典的應用場景來講,單例模式在不考慮靜態構造函數實現的方式下,用鎖實現是必須的。好比:html

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)是最優雅的使用方式。this

Net3.5中的ReaderWriterLockSlim

ReaderWriterLockSlim支持三種鎖定模式
1. Read
2. Write
3. UpgradeableRead
這三種鎖定模式所對應的方法分別是:
1. EnterReadLock
2. EnterWriteLock
3. EnterUpgradeableReadLock線程

其中,Read模式是共享鎖定模式,任意線程均可以在此模式下同時得到鎖。
Write模式是互斥模式,任意數量線程只容許一個線程進入該鎖。code

其實這篇博文的目的,就是爲了測試傳統Object_lock 和ReaderWriteLockSlim的性能差別。廢話很少,實現上使用了趙姐夫的CodeTimerhtm

測試代碼以下:對象

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

使用控制檯應用程序blog

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.

相關文章
相關標籤/搜索