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


本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏MasiMaro 的技术博文

PE解析器的编写(四)——数据目录表的解析

在PE结构中最重要的就是区块表和数据目录表,上节已经说明了如何解析区块表,下面就是数据目录表,在数据目录表中一般只关心导入表,导出表和资源这几个部分,但是资源实...

32420
来自专栏哈雷彗星撞地球

RunLoop总结:RunLoop 与GCD 、Autorelease Pool之间的关系

如果在面试中问到RunLoop相关的知识,很有可能也会问到RunLoop与GCD、Autorelease Pool有没有关系,哪些地方用到了GCD、Autore...

12340
来自专栏jeremy的技术点滴

JVM的Finalization Delay引起的OOM

44380
来自专栏WindCoder

java基于SSM的Quartz计划任务配置

想找下Quartz的资料看下,某度,随之眼瞎,你们copy就算了,就不能用心点么,连个代码高亮都不忍心加,实在没心情看下去,但还是要忍一下,待我整理完整,再也不...

35910
来自专栏高爽的专栏

Nested-Loop Join Algorithms

MySQL使用嵌套循环算法来实现多表之间的联接。 Nested-Loop Join Algorithms 一个简单的嵌套循环联接(NLJ)算法,循环从第一个表中...

28100
来自专栏林德熙的博客

Windows 10 16251 添加的 api 工具

本文主要讲微软最新的sdk添加的功能,暂时还不能下载,到 7月29 ,现在可以下载是 16232 ,支持Neon效果。 实际上设置软件最低版本为 16232 就...

16210
来自专栏源码之家

word如何自动分割成多个文档

49450
来自专栏iOS开发

iOS开发之 Method Swizzling 深入浅出

如果产品经理突然说:"在所有页面添加统计功能,也就是用户进入这个页面就统计一次"。我们会想到下面的一些方法:

49870
来自专栏me的随笔

.NET中数据访问方式(一):LINQ

语言集成查询(Language-Integrated Query),简称LINQ,.NET中的LINQ体系如下图所示:

10330
来自专栏java一日一条

深入分析Java ClassLoader原理

大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用...

12320

扫码关注云+社区

领取腾讯云代金券