<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      謹慎使用 ConcurrentDictionary.Values

      謹慎使用 C# 中的 ConcurrentDictionary.Values

      在多線程開發中,ConcurrentDictionary 是一個非常重要的數據結構,它提供了線程安全的字典操作。然而,在使用其 Values 屬性時,我們需要格外小心,特別是在處理大數據量的場景中。本文通過一個示例程序分析了 ConcurrentDictionary.Values 的潛在問題,并探討了優化方案。

      • 問題描述

        以下是一個簡單的示例程序,它展示了在多線程環境中頻繁調用 ConcurrentDictionary.Values 時的內存波動現象:

        internal class Program
        {
          static void Main(string[] args)
          {
              Parallel.For(1, 100000, i =>
              {
                  Test();
                  Console.WriteLine($"第{i}次調用");
              });
              Console.WriteLine("Hello, World!");
              Console.ReadLine();
          }
        
          public static void Test()
          {
              var query = CacheHelper.GetAll();
              Console.WriteLine($"{query.Count}");
              Thread.Sleep(100);
          }
        }
        
        public class CacheHelper
        {
          static ConcurrentDictionary<string, string> allDic = new ConcurrentDictionary<string, string>();
        
          static CacheHelper()
          {
              for (int i = 0; i < 80000; i++)
              {
                  allDic.TryAdd(i.ToString(), string.Join(",", Enumerable.Range(0, 500)));
              }
          }
        
          public static ICollection<string> GetAll()
          {
              return allDic.Values;
          }
        }
        
      • 現象分析

        內存.png

        運行上述代碼后,可以觀察到程序內存占用不斷上升,達到一個高峰后,內存被回收,但隨后繼續增長。這種內存波動在處理大字符串時尤為明顯。通過 dotMemory 查看內存情況,如上圖

      • 源碼分析

        通過查看 ConcurrentDictionary 的源碼,可以清楚地理解 Values 屬性的工作機制:

        private ReadOnlyCollection<TValue> GetValues()
        {
          int locksAcquired = 0;
          try
          {
              AcquireAllLocks(ref locksAcquired);
              int countNoLocks = GetCountNoLocks();
              if (countNoLocks == 0)
              {
                  return ReadOnlyCollection<TValue>.Empty;
              }
              TValue[] array = new TValue[countNoLocks];
              int num = 0;
              VolatileNode[] buckets = _tables._buckets;
              for (int i = 0; i < buckets.Length; i++)
              {
                  VolatileNode volatileNode = buckets[i];
                  for (Node node = volatileNode._node; node != null; node = node._next)
                  {
                      array[num] = node._value;
                      num++;
                  }
              }
              return new ReadOnlyCollection<TValue>(array);
          }
          finally
          {
              ReleaseLocks(locksAcquired);
          }
        }
        
      • 關鍵點

      • 每次調用 Values 都會重新生成一個新數組

        TValue[] array = new TValue[countNoLocks];
        

        這意味著每次獲取 Values 都會創建一個新的 TValue[],而不是返回 ConcurrentDictionary 內部的引用。這可能是為了線程安全而設計的,但在高并發場景下會導致頻繁的內存分配。

      • 存儲對象的大小和數量會加劇問題
        在示例程序中,ConcurrentDictionary 存儲了大量的長字符串。這使得每次調用 Values 時,生成的臨時數組占用大量內存,GC 回收的壓力顯著增加。

      • 早期版本的實現對比
        在 .NET 5 中,類似的邏輯使用了 List<TValue>,其本質行為與當前版本一致,依然會重新創建一個臨時容器。

      • 場景優化建議

        針對上述問題,我們可以采取以下優化方案:

      • 1. 避免頻繁調用 ConcurrentDictionary.Values

        在數據量較大或高并發場景中,盡量避免直接使用 ConcurrentDictionary.Values。根據具體需求,設計更高效的數據訪問方式。

      • 2. 使用 lock + Dictionary 替代

        Dictionary 本身不是線程安全的,但其 Values 屬性返回的是字典內部的引用,而不會重新分配內存。在某些場景下,可以采用 lock + Dictionary 替代。

        示例代碼如下:

        public class CacheHelper
        {
          private static Dictionary<string, string> allDic = new Dictionary<string, string>();
          private static readonly object lockObj = new object();
        
          static CacheHelper()
          {
              for (int i = 0; i < 80000; i++)
              {
                  allDic.Add(i.ToString(), string.Join(",", Enumerable.Range(0, 500)));
              }
          }
        
          public static ICollection<string> GetAll()
          {
              lock (lockObj)
              {
                  return allDic.Values;
              }
          }
        }
        

        通過這種方式,我們可以避免每次調用 Values 時分配大量新對象,同時保證線程安全。


      • 總結

        ConcurrentDictionary 是一個強大的線程安全數據結構,但在高并發、大數據量的場景下,使用其 Values 屬性時需特別注意。通過了解其底層實現和內存分配機制,我們可以采取以下優化策略:

        1. 減少 Values 的調用頻率,避免頻繁分配臨時內存。
        2. 在合適的場景下使用 lock + Dictionary 替代,既能保證線程安全,又能減少 GC 壓力。

        合理利用工具(如 dotMemory)分析內存行為,將有助于定位和優化類似問題。

      • ## 參考鏈接
        http://www.rzrgm.cn/huangxincheng/p/15329098.html

      posted @ 2025-01-11 23:30  dotNet編程拾光  閱讀(146)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲一线二线三线品牌精华液久久久| 国内精品久久久久电影院| 中文字幕有码无码AV| 精品国产精品午夜福利| 国产女主播喷水视频在线观看| 国产日产亚洲系列av| 久久亚洲精品中文字幕波多野结衣| 国语自产精品视频在线看| 亚洲成在人线在线播放无码| 国产视频一区二区在线看| 色偷偷亚洲女人天堂观看| 草草线在成年免费视频2| 一区二区三区国产不卡| 亚洲日本韩国欧美云霸高清| 亚洲人成人一区二区三区| 欧美国产日韩久久mv| 国产午夜精品理论大片| 国产精品白浆无码流出| 欧美喷水抽搐magnet| 国产69精品久久久久99尤物 | 亚洲一区二区精品偷拍| 天天拍夜夜添久久精品大| 国产高清在线精品一区二区三区| 视频一区二区三区自拍偷拍| 91中文字幕在线一区| 中文字幕无码人妻aaa片| 国产精品国产高清国产专区| 国产福利微视频一区二区| 久久这里有精品国产电影网 | 精品精品亚洲高清a毛片| 亚洲AV日韩AV激情亚洲| 午夜精品极品粉嫩国产尤物| 无码人妻精品一区二区三区蜜桃| 亚洲av综合av一区| 日韩女同一区二区三区久久| 亚洲精品成人7777在线观看| 永久免费在线观看蜜桃视频| 亚洲欧洲久久激情久av| 男女男免费视频网站国产| 亚洲精品在线二区三区| 精品日韩亚洲av无码|