这里我们又复习了ThreadStatic
特性,用于存储线程唯一的对象 。大家看到这个设计就知道,它是存在于每个线程的StringBuilder
缓存,意味着只要是一个线程中需要使用的代码都可以复用它,不过它的是复用小于360个字符StringBuilder
, 这个能满足绝大多数场景的使用,当然大家也可以根据自己项目实际情况,调整它的大小 。
要使用的话 , 很简单,我们只需要把这个类拷贝出来,变成一个公共的类,然后使用相同的测试代码即可 。
文章插图
跑分及总结【.NET性能优化-复用StringBuilder】按照惯例,跑个分看看,这里模拟的是小字符串拼接场景:
using System.Text;using BenchmarkDotNet.Attributes;using BenchmarkDotNet.Order;using BenchmarkDotNet.Running;using Microsoft.Extensions.ObjectPool;BenchmarkRunner.Run<Bench>();[MemoryDiagnoser][HtmlExporter][Orderer(SummaryOrderPolicy.FastestToSlowest)]public class Bench{ private readonly int[] _arr = Enumerable.Range(0,50).ToArray(); [Benchmark(Baseline = true)] public string UseStringBuilder() {return RunBench(new StringBuilder(16)); } [Benchmark] public string UseStringBuilderCache() {var builder = StringBuilderCache.Acquire(16);try{return RunBench(builder);}finally{StringBuilderCache.Release(builder);} } private readonly ObjectPool<StringBuilder> _pool = new DefaultObjectPoolProvider().CreateStringBuilderPool(16, 256); [Benchmark] public string UseStringBuilderPool() {var builder = _pool.Get();try{return RunBench(builder);}finally{_pool.Return(builder);} } public string RunBench(StringBuilder buider) {for (int i = 0; i < _arr.Length; i++){buider.Append(i);}return buider.ToString(); }}
结果如下所示 , 和我们想象中的差不多 。文章插图
根据实际的高性能编程来说:
- 代码中没有
async/await
最佳是使用ValueStringBuilder
,前面文章也说明了这一点 - 代码中尽量复用
StringBuilder
,不要每次都new()
创建它 - 在方便依赖注入的场景 , 可以多使用
StringBuilderPool
这个池化类 - 在不方便依赖注入的场景,使用
StringBuilderCache
会更加方便
StringBuilderCache
的MaxBuilderSize
和StringBuilderPool
的MaxSize
都快可以根据项目类型和使用调整,像我们实际中一般都会调整到256KB甚至更大 。附录本文源码链接:https://github.com/InCerryGit/RecycleableStringBuilderExample
推荐阅读
- .net 温故知新:【8】.NET 中的配置从xml转向json
- UE优化性能
- 来啦来啦|开源 * 安全 * 赋能 - .NET Conf China
- 三星s21ultra和苹果12promax性能对比_三星s21ultra和苹果12promax谁的性能好
- 如何在.NET程序崩溃时自动创建Dump?
- .NET Conf 2022 &ndash; 11 月 8 日至 10 日
- .NET 零开销抽象指南
- 二、.Net Core搭建Ocelot
- 创建.NET程序Dump的几种姿势
- m1x芯片和m1区别_哪个性能更强