.NET性能优化-复用StringBuilder( 二 )

这里我们又复习了ThreadStatic特性,用于存储线程唯一的对象 。大家看到这个设计就知道,它是存在于每个线程的StringBuilder缓存,意味着只要是一个线程中需要使用的代码都可以复用它,不过它的是复用小于360个字符StringBuilder , 这个能满足绝大多数场景的使用,当然大家也可以根据自己项目实际情况,调整它的大小 。
要使用的话 , 很简单,我们只需要把这个类拷贝出来,变成一个公共的类,然后使用相同的测试代码即可 。

.NET性能优化-复用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(); }}结果如下所示 , 和我们想象中的差不多 。
.NET性能优化-复用StringBuilder

文章插图
根据实际的高性能编程来说:
  • 代码中没有async/await最佳是使用ValueStringBuilder,前面文章也说明了这一点
  • 代码中尽量复用StringBuilder,不要每次都new()创建它
  • 在方便依赖注入的场景 , 可以多使用StringBuilderPool这个池化类
  • 在不方便依赖注入的场景,使用StringBuilderCache会更加方便
另外StringBuilderCacheMaxBuilderSizeStringBuilderPoolMaxSize都快可以根据项目类型和使用调整,像我们实际中一般都会调整到256KB甚至更大 。
附录本文源码链接:https://github.com/InCerryGit/RecycleableStringBuilderExample

推荐阅读