C# 字典 Dictionary 的 TryGetValue 與先判斷 ContainsKey 然後 Get 的性能對比

本文使用 benchmarkdotnet 測試字典的性能,在使用字典獲取一個可能存在的值的時候可以使用兩個不同的寫法,於是本文分析兩個寫法的性能。

判斷值存在,如果值存在就獲取值,可以使用下面兩個不同的方法

一個方法是使用 TryGetValue 請看下面代碼

            if (Dictionary.TryGetValue(xx, out var foo))
            {
            }

另一個方法是先判斷是否存在然後再獲取,請看下面代碼

if(Dictionary.ContainsKey(xx))
{
	var foo = Dictionary[xx];
}

於是本文就使用benchmarkdotnet 測試兩個方法的性能

下面是進行測試的數據,測試的代碼放在本文的最後。這裏的 TryGetExist 方法就是嘗試獲取一個值,這個值是存在的。而 ContainGetExist 是先判斷值是否存在,如果存在就嘗試獲取這個值。

BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134
Intel Core i7-6700 CPU 3.40GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
Frequency=3328130 Hz, Resolution=300.4690 ns, Timer=TSC
  [Host]     : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3132.0  [AttachedDebugger]
  DefaultJob : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3132.0

Method

Mean

Error

StdDev

Median

TryGetExist

30.26 ns

0.6057 ns

0.5949 ns

30.11 ns

ContainGetExist

46.36 ns

1.0883 ns

3.1919 ns

44.90 ns

TryGetNoExist

20.23 ns

0.4661 ns

0.7658 ns

19.93 ns

ContainGetNoExist

18.68 ns

0.2569 ns

0.2403 ns

18.66 ns

同樣對比 ConcurrentDictionary 線程安全的類的性能,也就是將會上面的 Foo 測試類的字典替換爲 ConcurrentDictionary 其他代碼都不修改,下面是測試的數據,可以看到使用 TryGetValue 的性能依然比較好

BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134
Intel Core i7-6700 CPU 3.40GHz (Skylake), 1 CPU, 8 logical and 4 physical cores
Frequency=3328130 Hz, Resolution=300.4690 ns, Timer=TSC
  [Host]     : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3132.0  [AttachedDebugger]
  DefaultJob : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3132.0

Method

Mean

Error

StdDev

Median

TryGetExist

31.20 ns

0.4644 ns

0.3625 ns

31.17 ns

ContainGetExist

66.80 ns

2.4692 ns

7.2806 ns

63.84 ns

TryGetNoExist

20.07 ns

0.1254 ns

0.1112 ns

20.04 ns

ContainGetNoExist

27.63 ns

0.4230 ns

0.3956 ns

27.65 ns

所有代碼

    public class Foo
    {
        /// <inheritdoc />
        public Foo()
        {
            var ran = new Random();
            bool set = false;
            for (int i = 0; i < 100000; i++)
            {
                LazyDictionary[ran.Next().ToString() + "-" + i.ToString()] = ran.Next().ToString();
                if (!set)
                {
                    if (ran.Next() < i)
                    {
                        set = true;
                        LazyDictionary["lindexi"] = "逗比";
                    }
                }
            }
        }

        [Benchmark]
        public void TryGetExist()
        {
            if (LazyDictionary.TryGetValue("lindexi", out var foo))
            {
                _foo = foo;
            }
        }

        [Benchmark]
        public void ContainGetExist()
        {
            if (LazyDictionary.ContainsKey("lindexi"))
            {
                _foo = LazyDictionary["lindexi"];
            }
        }


        [Benchmark]
        public void TryGetNoExist()
        {
            if (LazyDictionary.TryGetValue("lindexi123", out var foo))
            {
                _foo = foo;
            }
        }

        [Benchmark]
        public void ContainGetNoExist()
        {
            if (LazyDictionary.ContainsKey("lindexi123"))
            {
                _foo = LazyDictionary["lindexi123"];
            }
        }

        private object _foo;

        private Dictionary<string, object> LazyDictionary { get; } = new Dictionary<string, object>();

    }

我的博客即將搬運同步至騰訊雲+社區,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=19bm8i8js1ezb


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章