zoukankan      html  css  js  c++  java
  • C# 的 Dictionary 寫入前應注意事項

    一個已上線、用戶龐大的系統,幾個月來第一次出現這個系統錯誤訊息 :

    「已經加入含有相同索引鍵的項目」
    「已添加了具有相同键的项」
    An item with the same key has already been added.

    ----------------------------------------------------------------------------
    分析原因:

    C# 的 Dictionary 這種資料結構的變數,若宣告為 static,在使用上,要注意寫入或 Add 資料前,只做 if ContainsKey 判斷是不夠的 (如下圖 2),因其不是「執行緒 ; 线程」(thread) 安全的。由於 Dictionary 的 Key 不能重複,若剛好有兩人或多人,同時進入 if 區塊、同時 Add 同一個 Key,就會引發錯誤。機率不高,但久久偶爾會發生一次。

    因此在 Dictionary 寫入或 Add 前,應多做一個 lock 的動作,如下圖 3,以達到一次只有一個人 (一個執行緒),能進入 lock 區塊中,其他人要排隊等候。


    圖 1 宣告 Dictionary 變數



    圖 2 改寫前 (久久偶爾會發生一次錯誤的寫法)



    圖 3 改寫後


    C# 的 lock,但注意一定要是宣告為 static 的變數,才有鎖定的結果 (經我自己實測)。
    (static 變數,表示全網站的所有用戶,共用同一塊「記憶體 ; 内存」(memory),而不是每個用戶各自 new 一塊記憶體)。

    -------------------------------------------------------------------
    Dictionary 介紹 (msdn) :
    https://msdn.microsoft.com/zh-tw/library/xfhwa508(v=vs.110).aspx
    -------------------------------------------------------------------
    詳細說明 Dictionary 問題的文章 (推薦好文,台灣極資深專家-李明儒先生):
    http://blog.darkthread.net/post-2012-01-31-dictionary-thread-safe.aspx

    以下引用該文的內容:

    Dictionary<TKey, TValue>在多執行緒下,「讀取」沒問題;但若打算在多個執行緒中同時「更新」,就必須自行處理鎖定及同步議題

    上文中,還提到 .NET 4.0 加入一種新的 System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>。
    但我爬文後,覺得不見得能解決此問題,建議勿用。
    -------------------------------------------------------------------
    lock 介紹 :
    http://www.dotblogs.com.tw/yc421206/archive/2011/01/07/20624.aspx
    https://msdn.microsoft.com/zh-tw/library/c5kehkcz.aspx
    -------------------------------------------------------------------
    ConcurrentDictionary<TKey, TValue> 類別 :
    https://msdn.microsoft.com/zh-tw/library/dd287191(v=vs.110).aspx

    ConcurrentDictionary<TKey, TValue>.GetOrAdd 方法 (TKey, TValue) :
    https://msdn.microsoft.com/zh-tw/library/ee378674(v=vs.110).aspx

    Dictionary + Locking versus ConcurrentDictionary
    http://www.codeproject.com/Articles/548406/Dictionary-plus-Locking-versus-ConcurrentDictionar
    -------------------------------------------------------------------
    ConcurrentDictionary 让你的多线程代码更优美
    http://www.bkjia.com/C_jc/968538.html

    以下引用該文的內容 (非我本人的觀點):

    用 Dictionary,而当这个属性被提升为 static 静态的(类级别的)时候,我们就要考虑它的线程安全性了,因为它有可能被多个线程同时访问,当然,如果这个对象是只读的,也无所谓线程安全,但如果这个属性是可以被写的,那就需要把它加锁了。
    但从性能上看,就不能被接收,我们知道,lock 会把其它线程锁在外面,无论是读还是写,都会被锁,性能非常差。

    -------------------------------------------------------------------

  • 相关阅读:
    MVC中添加执行统计功能
    SVN 全局忽略列表
    WebApi当中微软又犯了一次2
    SQL性能更总
    【懒人专用】快速构建Web请求
    js中模拟多个字母的split
    分页起始位置的懒汉判断方法
    文档摆放
    转: 多线程环境下调用 HttpWebRequest 并发连接限制
    bash命令根据历史记录补全
  • 原文地址:https://www.cnblogs.com/WizardWu/p/4595161.html
Copyright © 2011-2022 走看看