您现在的位置是:首页 > 编程 > 

使用 .ET 8 中的 FrozenCollection

2025-07-26 08:48:47
使用 .ET 8 中的 FrozenCollection 使用 .ET 8 中的 FrozenCollectionIntro.ET 8 中引入了 FrozenCollection 使得只读 Collection 的操作性能更加好了,Stephen 在 .ET 8 的性能改进博客中也有提到,在只读的场景可以考虑使用 FrozenSet/FrozenDictionary 来提升性能Frozen

使用 .ET 8 中的 FrozenCollection

使用 .ET 8 中的 FrozenCollection

Intro

.ET 8 中引入了 FrozenCollection 使得只读 Collection 的操作性能更加好了,Stephen 在 .ET 8 的性能改进博客中也有提到,在只读的场景可以考虑使用 FrozenSet/FrozenDictionary 来提升性能

FrozenSet vs ImmutableHashSet

FrozenSet/FrozenDictionary 实现大致原理差不多,所以我们以 FrozenSet 来分析

很多人可能会问不是已经有了 ImmutableHashSet/ImmutableDictionary 吗,为什么还要引入 FrozenSet/FrozenDictinary 呢?我也有着同样的问题,其实仔细看 Stephen 的博客的话其实有解释的

The collecti in System.Collecti.Frozen are immutable, just as are those in System.Collecti.Immutable, but they’re optimized for a different scenario. Whereas the purpose of a type like ImmutableDictionary<TKey, TValue> is to enable efficient mutation (into a new instance), the purpose of FrozenDictionary<TKey, TValue> is to represent data that never changes, and thus it doesn’t expose any operati that suggest mutation, only operati for reading. Maybe you’re loading some configuration data into a dictionary once when your process starts (and then re-loading it only rarely when the configuration changes) and then querying that data over and over and over again. Maybe you’re creating a mapping from HTTP status codes to delegates representing how those status codes should be handled. Maybe you’re caching schema information about a set of dynamically-discovered types and then using the resulting parsed information every time you encounter those types later on. Whatever the scenario, you’re creating an immutable collection that you want to be optimized for reads, and you’re willing to spend some more cycles creating the collection (because you do it only once, or only once in a while) in order to make reads as fast as possible. That’s exactly what FrozenDictionary<TKey, TValue> and FrozenSetprovide.

System.Collecti.Frozen 中的集合是不可变的,就像 System.Collecti.Immutable 中的集合一样,但它们针对不同的场景进行了优化。ImmutableDictionary<TKey, TValue> 等类型的目的在于实现高效变异(进入新实例),而 FrozenDictionary<TKey, TValue> 的目的在于表示永不改变的数据,因此它不会公开任何暗示变异的操作,只公开读取操作。也许您在进程启动时将一些配置数据加载到字典中一次(然后仅在配置更改时偶尔重新加载它),然后一遍又一遍地查询该数据。也许您正在创建从 HTTP 状态代码到代表应如何处理这些状态代码的委托的映射。也许您正在缓存有关一组动态发现的类型的架构信息,然后在以后每次遇到这些类型时使用生成的解析信息。无论哪种情况,您都会创建一个不可变集合,并希望对其进行优化以进行读取,并且您愿意花费更多周期来创建该集合(因为您只执行一次或偶尔执行一次),以便尽可能快地进行读取。这正是 FrozenDictionary<TKey, TValue> 和 FrozenSet所提供的。

我们可以看下他们的实现代码

ImmutableHashSet

FrozenSet

可以看到 ImmutableHashSet 虽然是不可变的,在它的基础上 Add/Remove 会创建新的对象,这也造成的 ImmutableHashSet 的复杂,而我们去看 FrozenSet 可以看到它的 Add/Remove 实现并没有实现,直接 throw 了 otSupportedException

Benchmark

我们来对 HashSet/ImmutableHashSet/FrozenSet 做一个查的基准测试,测试代码如下:

代码语言:javascript代码运行次数:0运行复制
[MemoryDiagnoser]
[SimpleJob]
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory), CategoriesColumn] // 
publicclassFrozenSetTest
{
    private HashSet<string> _hashSet;
    private ImmutableHashSet<string> _immutableHashSet;
    private FrozenSet<string> _frozenSet;

    [GlobalSetup]
    public void Setup()
    {
        var array = Enumerable.Range(0, 10).Select(x => x.ToString()).ToArray();
        _hashSet = array.ToHashSet();
        _immutableHashSet = array.ToImmutableHashSet();
        _frozenSet = array.ToFrozenSet();
    }
    
    [Benchmark(Baseline = true)]
    [BenchmarkCategory("Contains")]
    public bool FrozenSetContains()
    {
        return _frozenSet.Contains("6");
    }
    
    [Benchmark]
    [BenchmarkCategory("Contains")]
    public bool HashSetContains()
    {
        return _hashSet.Contains("6");
    }
    
    [Benchmark]
    [BenchmarkCategory("Contains")]
    public bool ImmutableHashSetContains()
    {
        return _immutableHashSet.Contains("6");
    }
    
    [Benchmark(Baseline = true)]
    [BenchmarkCategory("otContains")]
    public bool FrozenSetotContains()
    {
        return _frozenSet.Contains("-1");
    }
    
    [Benchmark]
    [BenchmarkCategory("otContains")]
    public bool HashSetotContains()
    {
        return _hashSet.Contains("-1");
    }
    
    [Benchmark]
    [BenchmarkCategory("otContains")]
    public bool ImmutableHashSetotContains()
    {
        return _immutableHashSet.Contains("-1");
    }
}

这里的基准测试分成了两个 category,这里也分享下如何在一个 benchmark 类型中声明两组 benchmark

可以通过 BenchmarkCategory 来设置并指定 GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory),这样在每个 category 下都可以有一个 Baseline

测试结果如下:

benchmark

从上述结果可以看得出来,Contains/otContains 这两种均是 FrozenSet 的性能更加优秀,Dictionary 大家可以自己动动手尝试一下

除了前面说的 FrozenSet 没有 ImmutableHashSet 支持 Add/Remove 之外,FrozenSet/FrozenDictionary 也通过算法为只读做了更多的优化所以有更好的性能

所以在遇到只读 collection 判断的时候,可以使用 FrozenSet 代替 HashSet/ImmutableHashSet, 使用 FrozenDictionary 代替 Dictionary/ImmutableDictionary 来改进性能

References
  • .cs
  • .Artifacts/results/PerformanceTest.CollectionTest.
本文参与 腾讯云自媒体同步曝光计划,分享自。原始发表:2025-01-22,如有侵权请联系 cloudcommunity@tencent 删除测试集合数据性能优化

#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格

本文地址:http://www.dnpztj.cn/biancheng/1141377.html

相关标签:无
上传时间: 2025-07-19 07:19:43
留言与评论(共有 6 条评论)
本站网友 京海铭筑
27分钟前 发表
就像 System.Collecti.Immutable 中的集合一样
本站网友 怎么去细纹
12分钟前 发表
也许您正在缓存有关一组动态发现的类型的架构信息
本站网友 什么叫车震
19分钟前 发表
原始发表:2025-01-22
本站网友 驻马店二手房
26分钟前 发表
原始发表:2025-01-22
本站网友 络石藤
2分钟前 发表
ImmutableDictionary<TKey