昨天看到关于字符串操作性能优化的帖子。
1.使用值类型的ToString方法
首先理解装箱和拆箱:1.装箱在值类型向引用类型转换时发生。2. 拆箱在引用类型向值类型转换时发生。装箱操作和拆箱操作是要额外耗费cpu和内存资源的,所以在c# 2.0之后引入了泛型来减少装箱操作和拆箱操作消耗。
值类型ToString是不会装箱。例如:string a = a + 1;和string a= a + 1.tostring();前者会引起装箱额外消耗资源。
2.运用StringBuilder类
String是不可变的。 对象是不可变的。 每次使用 System.String 类中的一个方法时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。 在需要对字符串执行重复修改的情况下,与创建新的 String 对象相关的系统开销可能会非常大。 如果要修改字符串而不创建新的对象,则可以使用System.Text.StringBuilder 类。 例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder 类可以提升性能。
下面简单写个案例实践一下:
public class HomeController : Controller { public ActionResult Index() { return View(); } /// <summary> /// str + i引起装箱消耗额外资源 /// </summary> /// <param name="count"></param> /// <returns></returns> public string Test1(int count) { Stopwatch watch = Stopwatch.StartNew(); for (int i = 0; i < count; i++) { string a = "a"; a = a + 1; } watch.Stop(); float sec = watch.ElapsedMilliseconds / 1000.0f; return string.Format("耗时:{0}秒", sec); } /// <summary> /// 值类型ToString不会装箱 /// </summary> /// <param name="count"></param> /// <returns></returns> public string Test2(int count) { Stopwatch watch = Stopwatch.StartNew(); for (int i = 0; i < count; i++) { string a = "a"; a = a + 1.ToString(); } watch.Stop(); float sec = watch.ElapsedMilliseconds / 1000.0f; return string.Format("耗时:{0}秒", sec); } /// <summary> /// str + i引起装箱消耗额外资源 /// </summary> /// <param name="count"></param> /// <returns></returns> public string Test3(int count) { string str = ""; Stopwatch watch = Stopwatch.StartNew(); for (int i = 0; i < count; i++) { str = str + i; } watch.Stop(); float sec = watch.ElapsedMilliseconds / 1000.0f; return string.Format("耗时:{0}秒", sec); } /// <summary> /// 使用String,在内存中创建一个新的字符串对象 /// </summary> /// <param name="count"></param> /// <returns></returns> public string Test4(int count) { string str = ""; Stopwatch watch = Stopwatch.StartNew(); for (int i = 0; i < count; i++) { str = str + i.ToString(); } watch.Stop(); float sec = watch.ElapsedMilliseconds / 1000.0f; return string.Format("耗时:{0}秒", sec); } /// <summary> /// 使用StringBuilder /// </summary> /// <param name="count"></param> /// <returns></returns> public string Test5(int count) { System.Text.StringBuilder str = new System.Text.StringBuilder(); Stopwatch watch = Stopwatch.StartNew(); for (int i = 0; i < count; i++) { str.Append(i.ToString()); } string result = str.ToString(); watch.Stop(); float sec = watch.ElapsedMilliseconds / 1000.0f; return string.Format("耗时:{0}秒", sec); } }
多次运行结果可以看到Test1,Test2每次装箱引起性能消耗不是很大,当到100000000(一亿)时有一秒左右差距。Test4,Test5当运行10000时,差距零点几,当运行100000时使用StringBuilder明显性能提升,当然我们可能也用不到如此长的string字符串,以前有个项目sql语句非常复杂是通过StringBuilder拼接的,当时只知道照着用,现在才知道还可以略微提升性能。