c#中string拼接的效率分析
通过unity profiler测试的代码,及运行结果
using UnityEngine; using UnityEngine.Profiling; using System.Text; #if UNITY_5_5_OR_NEWER using TProfiler = UnityEngine.Profiling.Profiler; #else using TProfiler = UnityEngine.Profiler; #endif public namespace Test { /// string concat test public class TestString : MonoBehaviour { // Update is called once per frame void Update () { // loop 10000times for(int i = 0; i < 10000; ++i) { TestString(); } TestString10000(); } // object new once private StringBuilder _sb = new StringBuilder(); /// concat 10000 times private void TestString10000() { // + TProfiler.BeginSample("string.(10000+)"); string s1 = string.Empty; for(int i = 0; i < 10000; ++i) { s1 = s1 + ((int)Time.time).ToString(); } TProfiler.EndSample(); // StringBuilder Append TProfiler.BeginSample("StringBuilder.10000Append"); _sb.Clear(); for(int i = 0; i < 10000; ++i) { _sb.Append((int)Time.time); } string s2 = _sb.ToString(); TProfiler.EndSample(); } /// concat 3 parts private void TestString() { System.Random random = new System.Random(); // + TProfiler.BeginSample("string.(+)"); string s1 = "txt_pre_" + random.Next().ToString() + "_end"; TProfiler.EndSample(); // Concat TProfiler.BeginSample("string.Concat"); string s2 = string.Concat("txt_pre_", random.Next(), "_end"); TProfiler.EndSample(); // Concat ToString() TProfiler.BeginSample("string.Concat & int.ToString"); string s3 = string.Concat("txt_pre_", ((int)Time.time).ToString(), "_end"); TProfiler.EndSample(); // format TProfiler.BeginSample("string.Format"); string s4 = string.Format("txt_pre_{0}_end", (int)Time.time); TProfiler.EndSample(); // format ToString() TProfiler.BeginSample("string.Format & int.ToString"); string s5 = string.Format("txt_pre_{0}_end", ((int)Time.time).ToString()); TProfiler.EndSample(); // StringBuilder AppendFormat TProfiler.BeginSample("StringBuilder.AppendFormat & int.ToString"); _sb.Clear(); _sb.AppendFormat("txt_pre_{0}_end", ((int)Time.time).ToString()); string s6 = _sb.ToString(); TProfiler.EndSample(); // StringBuilder Append TProfiler.BeginSample("StringBuilder.Append"); _sb.Clear(); _sb.Append("txt_pre_"); _sb.Append((int)Time.time); _sb.Append("_end"); string s7 = _sb.ToString(); TProfiler.EndSample(); // StringBuilder Append ToString() TProfiler.BeginSample("StringBuilder.Append & int.ToString"); _sb.Clear(); _sb.Append("txt_pre_"); _sb.Append(((int)Time.time).ToString()); _sb.Append("_end"); string s8 = _sb.ToString(); TProfiler.EndSample(); // StringBuilder AppendNumber TProfiler.BeginSample("StringBuilder.AppendNumber"); _sb.Clear(); _sb.Append("txt_pre_"); _sb.AppendNumber((int)Time.time); _sb.Append("_end"); string s9 = _sb.ToString(); TProfiler.EndSample(); } } }
运行结果:
结果分析及结论:
1、string.Format和StringBuider.AppendFormat()
可读性好
堆内存开销高,因为Format需要额外的内存分配
运行效率低
建议:
【少用,慎用】
2、StringBuilder.Append
可读性一般
堆内存开销低
运行效率较高
建议:
大量字符串拼接时【必须使用】,内存及运行效率优化效果十分明显
少量字符串拼接时【酌情使用】,如调用频度
3、+和Concat
可读性较好
堆内存开销低
运行效率较高
在很多情况下,+会被优化为Concat
建议:
大量字符串拼接时【禁止使用】,内存及运行效率开销非常大,无法忍受
少量字符串拼接时【建议使用】
另外,对于string拼接时的int等基本数据类型,养成ToString()的习惯,避免Box操作带来的额外内存开销。
一个通用的int(Enum)转string的缓存方案
/// Sample for SimpleDictCache /// private static SimpleDictCache<EnumType> nameCache; /// 指挥官头像icon // public static string GetName(EnumType id) // { // if (nameCache == null) // nameCache = new SimpleDictCache<EnumType>(); // // return nameCache.Get((int)id, id, (o) => { // return o.ToString(); // 此处可以替换为复杂的获取string的实现 // }); // } /// 通用Dictionary<int, string>缓存 /// 比如enum对应的string可以用cache方式避免反复ToString()操作 class SimpleDictCache<T> { public delegate string CacheValue(T id); private Dictionary<int, string> data; public string Get(int k, T id, CacheValue cv) { if (data == null) data = new Dictionary<int, string>(); if (data.ContainsKey(k)) { return data[k]; } if (cv != null) data.Add(k, cv(id)); else data.Add(k, string.Empty); return data[k]; } }
作者:dongzee
出处:http://www.cnblogs.com/dongzee
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接
如有问题,可以通过 dongzee1984#gmail.com 联系我,非常感谢。