当前位置: 首页 > news >正文

嘉兴网站如何制作桂林网站制作公司华彩

嘉兴网站如何制作,桂林网站制作公司华彩,怎样做网络推广教学设计,地方门户网站有前景吗前言这一次要和大家分享的一个Tips是在字符串拼接场景使用的#xff0c;我们经常会遇到有很多短小的字符串需要拼接的场景#xff0c;在这种场景下及其的不推荐使用String.Concat也就是使用运算符。 目前来说官方最推荐的方案就是使用StringBuilder来构建这些字符串#xff…前言这一次要和大家分享的一个Tips是在字符串拼接场景使用的我们经常会遇到有很多短小的字符串需要拼接的场景在这种场景下及其的不推荐使用String.Concat也就是使用运算符。 目前来说官方最推荐的方案就是使用StringBuilder来构建这些字符串那么有什么更快内存占用更低的方式吗那就是今天要和大家介绍的ValueStringBuilder。ValueStringBuilderValueStringBuilder不是一个公开的API但是它被大量用于.NET的基础类库中由于它是值类型的所以它本身不会在堆上分配不会有GC的压力。 微软提供的ValueStringBuilder有两种使用方式一种是自己已经有了一块内存空间可供字符串构建使用。这意味着你可以使用栈空间也可以使用堆空间甚至非托管堆的空间这对于GC来说是非常友好的在高并发情况下能大大降低GC压力。// 构造函数传入一个Span的Buffer数组 public ValueStringBuilder(Spanchar initialBuffer);// 使用方式 // 栈空间 var vsb  new ValueStringBuilder(stackalloc char[512]); // 普通数租 var vsb  new ValueStringBuilder(new char[512]); // 使用非托管堆 var length  512; var ptr  NativeMemory.Alloc((nuint)(512 * Unsafe.SizeOfchar())); var span  new Spanchar(ptr, length); var vsb  new ValueStringBuilder(span); ..... NativeMemory.Free(ptr); // 非托管堆用完一定要Free另外一种方式是指定一个容量它会从默认的ArrayPool的char对象池中获取缓冲空间因为使用的是对象池所以对于GC来说也是比较友好的千万需要注意池中的对象一定要记得归还。// 传入预计的容量 public ValueStringBuilder(int initialCapacity)   {  // 从对象池中获取缓冲区_arrayToReturnToPool  ArrayPoolchar.Shared.Rent(initialCapacity);  ...... }那么我们就来比较一下使用、StringBuilder和ValueStringBuilder这几种方式的性能吧。// 一个简单的类 public class SomeClass   {  public int Value1; public int Value2; public float Value3;  public double Value4; public string? Value5; public decimal Value6;  public DateTime Value7; public TimeOnly Value8; public DateOnly Value9;  public int[]? Value10;   } // Benchmark类 [MemoryDiagnoser]   [HtmlExporter]   [Orderer(SummaryOrderPolicy.FastestToSlowest)]   public class StringBuilderBenchmark   {  private static readonly SomeClass Data;  static StringBuilderBenchmark()  {  var baseTime  DateTime.Now;  Data  new SomeClass  {  Value1  100, Value2  200, Value3  333,  Value4  400, Value5  string.Join(-, Enumerable.Range(0, 10000).Select(i  i.ToString())),  Value6  655, Value7  baseTime.AddHours(12),  Value8  TimeOnly.MinValue, Value9  DateOnly.MaxValue,  Value10  Enumerable.Range(0, 5).ToArray()  };  }// 使用我们熟悉的StringBuilder[Benchmark(Baseline  true)]  public string StringBuilder()  {  var data  Data;  var sb  new StringBuilder();  sb.Append(Value1:); sb.Append(data.Value1);  if (data.Value2  10)  {  sb.Append( ,Value2:); sb.Append(data.Value2);  }  sb.Append( ,Value3:); sb.Append(data.Value3);  sb.Append( ,Value4:); sb.Append(data.Value4);  sb.Append( ,Value5:); sb.Append(data.Value5);  if (data.Value6  20)  {  sb.Append( ,Value6:); sb.AppendFormat({0:F2}, data.Value6);  }  sb.Append( ,Value7:); sb.AppendFormat({0:yyyy-MM-dd HH:mm:ss}, data.Value7);  sb.Append( ,Value8:); sb.AppendFormat({0:HH:mm:ss}, data.Value8);  sb.Append( ,Value9:); sb.AppendFormat({0:yyyy-MM-dd}, data.Value9);  sb.Append( ,Value10:);  if (data.Value10 is null or {Length: 0}) return sb.ToString();  for (int i  0; i  data.Value10.Length; i)  {  sb.Append(data.Value10[i]);  }  return sb.ToString();  }// StringBuilder使用Capacity[Benchmark]  public string StringBuilderCapacity()  {  var data  Data;  var sb  new StringBuilder(20480);  sb.Append(Value1:); sb.Append(data.Value1);  if (data.Value2  10)  {  sb.Append( ,Value2:); sb.Append(data.Value2);  }  sb.Append( ,Value3:); sb.Append(data.Value3);  sb.Append( ,Value4:); sb.Append(data.Value4);  sb.Append( ,Value5:); sb.Append(data.Value5);  if (data.Value6  20)  {  sb.Append( ,Value6:); sb.AppendFormat({0:F2}, data.Value6);  }  sb.Append( ,Value7:); sb.AppendFormat({0:yyyy-MM-dd HH:mm:ss}, data.Value7);  sb.Append( ,Value8:); sb.AppendFormat({0:HH:mm:ss}, data.Value8);  sb.Append( ,Value9:); sb.AppendFormat({0:yyyy-MM-dd}, data.Value9);  sb.Append( ,Value10:);  if (data.Value10 is null or {Length: 0}) return sb.ToString();  for (int i  0; i  data.Value10.Length; i)  {  sb.Append(data.Value10[i]);  }  return sb.ToString();  }  // 直接使用拼接字符串[Benchmark]  public string StringConcat()  {  var str  ;  var data  Data;  str  (Value1:); str  (data.Value1);  if (data.Value2  10)  {  str   ,Value2:; str  data.Value2;  }  str   ,Value3:; str  (data.Value3);  str   ,Value4:; str  (data.Value4);  str   ,Value5:; str  (data.Value5);  if (data.Value6  20)  {  str   ,Value6:; str  data.Value6.ToString(F2);  }  str   ,Value7:; str  data.Value7.ToString(yyyy-MM-dd HH:mm:ss);  str   ,Value8:; str  data.Value8.ToString(HH:mm:ss);  str   ,Value9:; str  data.Value9.ToString(yyyy-MM-dd);  str   ,Value10:;  if (data.Value10 is not null  data.Value10.Length  0)  {  for (int i  0; i  data.Value10.Length; i)  {  str  (data.Value10[i]);  }     }  return str;  }  // 使用栈上分配的ValueStringBuilder[Benchmark]  public string ValueStringBuilderOnStack()  {  var data  Data;  Spanchar buffer  stackalloc char[20480];  var sb  new ValueStringBuilder(buffer);  sb.Append(Value1:); sb.AppendSpanFormattable(data.Value1);  if (data.Value2  10)  {  sb.Append( ,Value2:); sb.AppendSpanFormattable(data.Value2);  }  sb.Append( ,Value3:); sb.AppendSpanFormattable(data.Value3);  sb.Append( ,Value4:); sb.AppendSpanFormattable(data.Value4);  sb.Append( ,Value5:); sb.Append(data.Value5);  if (data.Value6  20)  {  sb.Append( ,Value6:); sb.AppendSpanFormattable(data.Value6, F2);  }  sb.Append( ,Value7:); sb.AppendSpanFormattable(data.Value7, yyyy-MM-dd HH:mm:ss);  sb.Append( ,Value8:); sb.AppendSpanFormattable(data.Value8, HH:mm:ss);  sb.Append( ,Value9:); sb.AppendSpanFormattable(data.Value9, yyyy-MM-dd);  sb.Append( ,Value10:);  if (data.Value10 is not null  data.Value10.Length  0)  {  for (int i  0; i  data.Value10.Length; i)  {  sb.AppendSpanFormattable(data.Value10[i]);  }     }  return sb.ToString();  }// 使用ArrayPool 堆上分配的StringBuilder[Benchmark]  public string ValueStringBuilderOnHeap()  {  var data  Data;  var sb  new ValueStringBuilder(20480);  sb.Append(Value1:); sb.AppendSpanFormattable(data.Value1);  if (data.Value2  10)  {  sb.Append( ,Value2:); sb.AppendSpanFormattable(data.Value2);  }  sb.Append( ,Value3:); sb.AppendSpanFormattable(data.Value3);  sb.Append( ,Value4:); sb.AppendSpanFormattable(data.Value4);  sb.Append( ,Value5:); sb.Append(data.Value5);  if (data.Value6  20)  {  sb.Append( ,Value6:); sb.AppendSpanFormattable(data.Value6, F2);  }  sb.Append( ,Value7:); sb.AppendSpanFormattable(data.Value7, yyyy-MM-dd HH:mm:ss);  sb.Append( ,Value8:); sb.AppendSpanFormattable(data.Value8, HH:mm:ss);  sb.Append( ,Value9:); sb.AppendSpanFormattable(data.Value9, yyyy-MM-dd);  sb.Append( ,Value10:);  if (data.Value10 is not null  data.Value10.Length  0)  {  for (int i  0; i  data.Value10.Length; i)  {  sb.AppendSpanFormattable(data.Value10[i]);  }     }return sb.ToString();  }}结果如下所示。从上图的结果中我们可以得出如下的结论。使用StringConcat是最慢的这种方式是无论如何都不推荐的。使用StringBuilder要比使用StringConcat快6.5倍这是推荐的方法。设置了初始容量的StringBuilder要比直接使用StringBuilder快25%正如我在你应该为集合类型设置初始大小[1]一样设置初始大小绝对是相当推荐的做法。栈上分配的ValueStringBuilder比StringBuilder要快50%比设置了初始容量的StringBuilder还快25%另外它的GC次数是最低的。堆上分配的ValueStringBuilder比StringBuilder要快55%他的GC次数稍高与栈上分配。 从上面的结论中我们可以发现ValueStringBuilder的性能非常好就算是在栈上分配缓冲区性能也比StringBuilder快25%。源码解析ValueStringBuilder的源码不长我们挑几个重要的方法给大家分享一下部分源码如下。// 使用 ref struct 该对象只能在栈上分配 public ref struct ValueStringBuilder {// 如果从ArrayPool里分配buffer 那么需要存储一下// 以便在Dispose时归还private char[]? _arrayToReturnToPool;// 暂存外部传入的bufferprivate Spanchar _chars;// 当前字符串长度private int _pos;// 外部传入bufferpublic ValueStringBuilder(Spanchar initialBuffer){// 使用外部传入的buffer就不使用从pool里面读取的了_arrayToReturnToPool  null;_chars  initialBuffer;_pos  0;}public ValueStringBuilder(int initialCapacity){// 如果外部传入了capacity 那么从ArrayPool里面获取_arrayToReturnToPool  ArrayPoolchar.Shared.Rent(initialCapacity);_chars  _arrayToReturnToPool;_pos  0;}// 返回字符串的Length 由于Length可读可写// 所以重复使用ValueStringBuilder只需将Length设置为0public int Length{get  _pos;set{Debug.Assert(value  0);Debug.Assert(value  _chars.Length);_pos  value;}}......[MethodImpl(MethodImplOptions.AggressiveInlining)]public void Append(char c){// 添加字符非常高效 直接设置到对应Span位置即可int pos  _pos;if ((uint) pos  (uint) _chars.Length){_chars[pos]  c;_pos  pos  1;}else{// 如果buffer空间不足那么会走GrowAndAppend(c);}}[MethodImpl(MethodImplOptions.AggressiveInlining)]public void Append(string? s){if (s  null){return;}// 追加字符串也是一样的高效int pos  _pos;// 如果字符串长度为1 那么可以直接像追加字符一样if (s.Length  1  (uint) pos  (uint) _chars .Length){_chars[pos]  s[0];_pos  pos  1;}else{// 如果是多个字符 那么使用较慢的方法AppendSlow(s);}}private void AppendSlow(string s){// 追加字符串 空间不够先扩容// 然后使用Span复制 相当高效int pos  _pos;if (pos  _chars.Length - s.Length){Grow(s.Length);}s #if !NETCOREAPP.AsSpan() #endif.CopyTo(_chars.Slice(pos));_pos  s.Length;}// 对于需要格式化的对象特殊处理[MethodImpl(MethodImplOptions.AggressiveInlining)]public void AppendSpanFormattableT(T value, string? format  null, IFormatProvider? provider  null)where T : ISpanFormattable{// ISpanFormattable非常高效if (value.TryFormat(_chars.Slice(_pos), out int charsWritten, format, provider)){_pos  charsWritten;}else{Append(value.ToString(format, provider));}}[MethodImpl(MethodImplOptions.NoInlining)]private void GrowAndAppend(char c){// 单个字符扩容在添加Grow(1);Append(c);}// 扩容方法[MethodImpl(MethodImplOptions.NoInlining)]private void Grow(int additionalCapacityBeyondPos){Debug.Assert(additionalCapacityBeyondPos  0);Debug.Assert(_pos  _chars.Length - additionalCapacityBeyondPos,Grow called incorrectly, no resize is needed.);// 同样也是2倍扩容默认从对象池中获取bufferchar[] poolArray  ArrayPoolchar.Shared.Rent((int) Math.Max((uint) (_pos  additionalCapacityBeyondPos),(uint) _chars.Length * 2));_chars.Slice(0, _pos).CopyTo(poolArray);char[]? toReturn  _arrayToReturnToPool;_chars  _arrayToReturnToPool  poolArray;if (toReturn ! null){// 如果原本就是使用的对象池 那么必须归还ArrayPoolchar.Shared.Return(toReturn);}}// [MethodImpl(MethodImplOptions.AggressiveInlining)]public void Dispose(){char[]? toReturn  _arrayToReturnToPool;this  default; // 为了安全在释放时置空当前对象if (toReturn ! null){// 一定要记得归还对象池ArrayPoolchar.Shared.Return(toReturn);}} }从上面的源码我们可以总结出ValueStringBuilder的几个特征比起StringBuilder来说实现方式非常简单。一切都是为了高性能比如各种Span的用法各种内联参数以及使用对象池等等。内存占用非常低它本身就是结构体类型另外它是ref struct意味着不会被装箱不会在堆上分配。适用场景ValueStringBuilder是一种高性能的字符串创建方式针对于不同的场景可以有不同的使用方式。1.非常高频次的字符串拼接的场景并且字符串长度较小此时可以使用栈上分配的ValueStringBuilder。 大家都知道现在ASP.NET Core性能非常好在其依赖的内部库UrlBuilder[2]中就使用栈上分配因为栈上分配在当前方法结束后内存就会回收所以不会造成任何GC压力。2.非常高频次的字符串拼接场景但是字符串长度不可控此时使用ArrayPool指定容量的ValueStringBuilder。比如在.NET BCL库中有很多场景使用比如动态方法的ToString[3]实现。从池中分配虽然没有栈上分配那么高效但是一样的能降低内存占用和GC压力。3. 非常高频次的字符串拼接场景但是字符串长度可控此时可以栈上分配和ArrayPool分配联合使用比如正则表达式[4]解析类中如果字符串长度较小那么使用栈空间较大那么使用ArrayPool。需要注意的场景1.在async\await中无法使用ValueStringBuilder。原因大家也都知道因为ValueStringBuilder是ref struct它只能在栈上分配async\await会编译成状态机拆分await前后的方法所以ValueStringBuilder不好在方法内传递不过编译器也会警告。2.无法将ValueStringBuilder作为返回值返回因为在当前栈上分配方法结束后它会被释放返回它将指向未知的地址。这个编译器也会警告。3.如果要将ValueStringBuilder传递给其它方法那么必须使用ref传递否则发生值拷贝会存在多个实例。这个编译器不会警告但是你必须非常注意。4. 如果使用栈上分配那么Buffer大小控制在5KB内比较稳妥至于为什么需要这样后面有机会在讲一讲。总结今天和大家分享了一下高性能几乎无内存占用的字符串拼接结构体ValueStringBuilder在大多数的场景还是推荐大家使用。但是要非常注意上面提到的[5]的几个场景如果不符合条件那么大家还是可以使用高效的StringBuilder来进行字符串拼接。本文源码链接: https://github.com/InCerryGit/BlogCode-Use-ValueStringBuilder参考资料[1] 你应该为集合类型设置初始大小: https://www.cnblogs.com/InCerry/p/Dotnet-Opt-Perf-You-Should-Set-Capacity-For-Collection.html[2] UrlBuilder: https://github.com/dotnet/runtime/blob/57bfe474518ab5b7cfe6bf7424a79ce3af9d6657/src/libraries/System.Private.Uri/src/System/UriBuilder.cs#L284-L362[3] ToString: https://github.com/dotnet/runtime/blob/43dd0a74ab524278620d8c6a9d33a9b73b2d2228/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.CoreCLR.cs#L137[4] 正则表达式: https://github.com/dotnet/runtime/blob/43dd0a74ab524278620d8c6a9d33a9b73b2d2228/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexParser.cs#L150[5] 上面提到的: #需要注意的场景
http://www.zqtcl.cn/news/848167/

相关文章:

  • 活动汪活动策划网站wordpress 无法保存
  • 门户网站开发案例兰州需要做网站的公司有哪些
  • 东莞企业网站asp网站怎么安装
  • 个人做公司网站网站备案取消接入
  • 崇信网站建设it外包的收益主要有哪些
  • 安陆做网站多少钱免费网站定制
  • 快递网站模版长春好的做网站公司有哪些
  • 怎么利用公司网站开发客户网站建设重点步骤
  • 网站站内推广用个人电脑做网站的步骤
  • 网站设计主要包含3个方面陕西城乡住房建设部网站
  • 专门做汽车配件的网站东莞招聘网有哪些比较好
  • 网站前台怎么套用织梦后台小网站怎么建设
  • 网站框架代码深圳手机网站设计
  • 更改网站主题九江建网站的公司
  • 如何分析一个网站网站页面建设
  • 做网站好网页制作3个网页的网站图片
  • 合肥网站建设网站推广新的网站建设一般多少钱
  • 北京网站改版哪家好网站关键词怎样做优化
  • 网站开发行业分析wordpress 粘贴表格
  • 网站开发的招标参数网络科技公司网站源码下载
  • 属于网络营销站点推广的是seo好wordpress主题
  • j2ee只做网站阿里企业邮箱免费
  • 做企业网站需要买什么资料室内设计学徒
  • 网站新增关键词设计公司logo公司文化
  • 怎么写一个网站程序农产品网站如何做地推
  • 北京网站优化服务商有了域名怎么建网站
  • 转运网站开发国外永久免费crm系统
  • 免费网站建设网站wordpress扁平化中文主题
  • 外贸企业网站策划个人简历模板免费可编辑
  • 自助建站免费建站免费建站工具有哪些