本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。

文章是哥(mephisto)写的,SourceLink

阅读目录

本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。

文章是哥(mephisto)写的,SourceLink

介绍

    自己对String和StringBuilder的处理机制略懂,大胆的设想下两者的性能对比会出现什么样的令人意外的情况。于是便有此文,结果我也不知道,那么我们就根据设计的测试用例来看看现象吧。本文耗时5个小时(包括测试用例),希望大家给点汗水的推荐。

环境搭建

一:搭建多Framework测试解决方案

  由于要测试多个Framework下的性能,所以就创建了个解决方案,版本包括:2.0,3.0,3.5,4.0,4.5。这么多的工程,测试起来也比较麻烦,俺还是耐心的进行了测试。

  IDE采用的VS2013,所以大家要下载后自己运行Demo,还是要注意下IDE版本,如是低版本,自己将4.5的移除即可

二:主要类及方法介绍

1:TestUtil类

  用于String和StringBuilder的创建的工具类

  1.1:CreateString()

  创建String方法

 1         public string CreateString(int num, string value)
2 {
3 string temp = string.Empty;
4 while (num > 0)
5 {
6 temp += value;
7 num--;
8 }
9
10 return temp;
11 }

  1.2:CreateStringBuilder()

  创建StringBuilder方法

 1         public string CreateStringBuilder(int num, string value)
2 {
3 StringBuilder sb = new StringBuilder();
4 while (num > 0)
5 {
6 sb.Append(value);
7 num--;
8 }
9
10 return sb.ToString();
11 }

  2:Test类

  2.1:RunStringMinInF2()

  运行String最小次数测试

 1         private static readonly int runCount = 10000000;
2 public static void RunStringMinInF2(TestUtil testUtil, string word)
3 {
4 DateTime date1 = DateTime.Now;
5
6 int i = runCount * 5;
7 while (i > 0)
8 {
9 testUtil.CreateString(2, word);
10 i--;
11 }
12 DateTime date2 = DateTime.Now;
13 Console.WriteLine("stringMin:" + (date2 - date1).TotalMilliseconds.ToString());
14 }

  2.2:RunSBMinInF2()

  运行StringBuilder最小次数测试

         public static void RunSBMinInF2(TestUtil testUtil, string word)
{
DateTime date1 = DateTime.Now; int i = runCount * ;
while (i > )
{
testUtil.CreateStringBuilder(, word);
i--;
}
DateTime date2 = DateTime.Now;
Console.WriteLine("stringbuilderMin:" + (date2 - date1).TotalMilliseconds.ToString());
}

  2.3:RunString10InF2()

  运行单个String实体调用10次相加测试

         public static void RunString10InF2(TestUtil testUtil, string word)
{
DateTime date1 = DateTime.Now; int i = runCount;
while (i > )
{
testUtil.CreateString(, word);
i--;
}
DateTime date2 = DateTime.Now;
Console.WriteLine("string10:" + (date2 - date1).TotalMilliseconds.ToString());
}

  2.4:RunSB10InF2()

  运行单个StringBuilder实体调用10次相加测试

         public static void RunSB10InF2(TestUtil testUtil, string word)
{
DateTime date1 = DateTime.Now; int i = runCount;
while (i > )
{
testUtil.CreateStringBuilder(, word);
i--;
}
DateTime date2 = DateTime.Now;
Console.WriteLine("stringbuilder10:" + (date2 - date1).TotalMilliseconds.ToString());
}

测试用例

一:在Framework2.0下最少字段数相加

  测试字符串:“a”

  单个实例测试数据次数:2

  被调用总次数:10000000

  测试代码如下:

 1     class Program
2 {
3 static void Main(string[] args)
4 {
5 TestUtil testUtil = new TestUtil();
6
7 Test.RunStringMinInF2(testUtil, "a");
8 Test.RunSBMinInF2(testUtil, "a");
9 Test.RunSBMinInF2(testUtil, "a");
10 Test.RunStringMinInF2(testUtil, "a");
11
12 Console.Read();
13 }
14 }

  防止由于先后调用原因,所以测试代码中同一个方法出现2次。多次运行,基本上结果差不多,同一次运行中也有数据相差的,但差别很小(几十ms)。

  运行截图如下:

  

  结果中在这样极端的考验StringBuilder性能的条件下,StringBuilder果然败下阵来。

二:在Framework2.0下最少字段数相加(字符串增加)

  测试字符串:“abcdefghijklmn1234567890opqrst~!@#^&*()”

  其他测试步骤:同测试方案一

  测试代码如下:

 1         static void Main(string[] args)
2 {
3 TestUtil testUtil = new TestUtil();
4
5 Test.RunStringMinInF2(testUtil, "abcdefghijklmn1234567890opqrst~!@#^&*()");
6 Test.RunSBMinInF2(testUtil, "abcdefghijklmn1234567890opqrst~!@#^&*()");
7 Test.RunSBMinInF2(testUtil, "abcdefghijklmn1234567890opqrst~!@#^&*()");
8 Test.RunStringMinInF2(testUtil, "abcdefghijklmn1234567890opqrst~!@#^&*()");
9
10 Console.Read();
11 }

  运行截图如下:

  

  很显然字符串增加了,对两者的处理时间都增加了,StringBuilder还是必然的败在阵来。

  三:在多Framework下最少字段数相加

  其他测试步骤:同测试方案一

  测试结果如下:

  

  发现在4.0和4.5的版本中StringBuilder是比原来的版本有一定优势的,在StringBuilder上4.0和4.5优势都很大,在String上4.5较其他版本略微有点优势。看来微软也是在进步啊,大家是不是很期待开源了的Framework,很多牛人可以对其进行贡献,那性能不是又进步了。

  四:在多Framework下最少字段数相加(字符串增加)

  其他测试步骤:同测试方案二

  测试结果如下:

  

  几个Framework版本结果差不多,但是在StringBuilder上4.0和4.5败在阵来,这是为什么列,大家思考一下,稍会作答。

  五:在Framework2.0下10字段数相加

  测试字符串:“a”

  单个实例测试数据次数:10

  被调用总次数:10000000

  测试代码如下:

 1     class Program
2 {
3 static void Main(string[] args)
4 {
5 TestUtil testUtil = new TestUtil();
6
7 Test.RunString10InF2(testUtil, "a");
8 Test.RunSB10InF2(testUtil, "a");
9 Test.RunSB10InF2(testUtil, "a");
10 Test.RunString10InF2(testUtil, "a");
11
12 Console.Read();
13 }
14 }

  测试结果如下:

  对单个实例调用次数增加,StringBuilder的优势就来了,渐渐的String就只能当吊车尾了。

  六:在Framework2.0下10字段数相加(字符串增加)

  测试字符串:“abcdefghijklmn1234567890opqrst~!@#^&*()”

  其他测试步骤:同测试方案五

  测试结果如下:

  这个测试很出乎意料啊,跟测试方案二,string的性能差别这么多,StringBuilder没什么差别,大家也可以思考下。

  

  七:在多Framework下10字段数相加

  其他测试步骤:同测试方案五

  测试结果如下:

  

  在众多Framework中,4.5和4.0拖妥妥的排在前2位。

  

  八:在多Framework下10字段数相加(字符串增加)

  其他测试步骤:同测试方案六

  测试结果如下:

  

  运行性能都差不多,区别不大。

MSDN说明

一:String和 StringBuilder的类型

  虽然 StringBuilder 和 String 两个表示字符序列,但它们以不同的方式实现。  String   是不可变的类型。  即看似修改 String 对象的每个操作实际创建新的字符串。

  对执行广泛的字符串操作实例 (如修改循环中的字符串) ,修改字符串能重复精确严重的性能损失。  方法是使用 StringBuilder,它是易失的字符串选件类。  可变性意味着,一旦选件类的实例创建的,则可以将其追加,取消,替换或插入字符修改。  StringBuilder   对象维护缓冲区容纳扩展到该字符串。  如果有足够的空间,新数据将被追加到缓冲区;否则,将分配一个新的、更大的缓冲区,原始缓冲区中的数据被复制到新的缓冲区,然后将新数据追加到新的缓冲区。

  虽然 StringBuilder 选件类比 String 选件类通常提供更好的性能,当不应使用 StringBuilder 自动替换 String 时,就要操作字符串。  性能取决于该字符串的大小,对新的字符串将分配的内存量,您的系统 app 的执行和操作的类型。  您应准备测试您的应用程序确定 StringBuilder 实际上是否可显着提高性能。

  

在这些条件下考虑使用 String 选件类:

  • 当您的应用程序将对字符串更改的数量很小。  在这些情况下,StringBuilder 不可能提供在 String的忽略或性能改进。

  • 当执行串联运算的内置的数字,尤其是对于字符串文本。  在这种情况下,编译器可能将串联运算到单个操作。

  • 当您生成字符串时,当您必须执行广泛的搜索操作。  StringBuilder   选件类没有搜索方法 ,如 IndexOf 或 StartsWith。  您必须转换为 String 的 StringBuilder 对象这些操作的,这样,可以对从使用 StringBuilder的性能。  有关详细信息,请参阅 搜索在 StringBuilder 对象的文本 部分。

在这些条件下考虑使用 StringBuilder 选件类:

  • 当您希望您的应用程序创建一个未知的设置为字符串的更改在设计时 (例如,当您使用循环连接包含用户输入的随机数字符串)。

  • 当您希望您的应用程序创建一个大量为字符串的更改。

  StringBuilder    对象的默认值容量为 16 个字符。

我的理解

  虽然String是引用类型,但是MS处理的时候,比如“+=”的运算符处理String的时候,是重新申请一块托管堆,用来存储处理后的新String,这样新String的HashCode(地址)也会随着变化,毕竟是一个新的地址引用,所以表面上很像是个“值类型”。

  因此,MS为了处理Sring带来的潜在性能问题,就加入了StringBuilder,当然我们这里自只用到了StringBuilder很少一部分功能(字符串相加),StringBuilder还有很多其他性能很好的功能(这里不表)。个人StringBuilder肯定比String复杂,初始化应该是要慢一点,确实我们在上面测试中的用例1,3告诉我们,两者实例化差距还是很大的。在处理多个字符串相加的时候,性能上还是StringBuilder要强些我的理解是:StringBulider的对面默认值容量是16个字符(Framework4.5),所以当处理的字符串大于16的时候,就会重新申请开辟另一块当前StringBuilder字符长度,(每当追加操作导致 StringBuilder 对象的长度超过其容量,其现有的容量翻倍),这是占一定的性能损耗的,而String每次都是申请一块托管堆,所以StringBuilder在多字符串处理的时候性能应该是大于等于String(不考虑内部算法逻辑,只是猜测)

  在不同的Framework中,StringBuilder的性能有时候很快,有时候很慢,这是可以理解的,毕竟设计一个类是有使用场景的,而已StringBuilder也提供了修改默认容量的方法,只是我们在使用的时候没有根据现实场景对这个进行设置。所以极小的字符串相加处理,就可以直接用String来用,但是如果非常频繁的处理,比如webApi被调用,那么是不是考虑用StringBuilder来,并且,通过测试来预估StringBuilder的默认容量范围,这样来达到性能的极致。

  在不同的Framework中,2.0比1.0是有个革命性的变化,比如泛型等等。3.0和3.5加了很多功能,比如WPF,WCF,WFF,Linq等,但他们只是在2.0的基础上做了扩展,丰富,实际底层改变不大,大家从3.0和3.5的安装版就可以看出,他们都是100多M,都是通过打补丁的方式来弄的,所以安装包很大。到了4.0,Framework发生的大变化,个人觉得最实质的变化就是引入了System.Core。并且把所有的都重新实现了一遍,所以安装版只有40多M,加了这么多东西,从28->40很是可以的。4.5没有研究,但从4.5引用的还是4.0的System.Core,就应该是底层变化不大,如果大家有知道,了解的,希望告诉下我们。所以上面结果中,有时候4.0,4.5领先很多,在有的时候落后很多,也没什么的,估计只是策略变了而已。

  Framework也开源了,大家都可以去关注下,我也会抽时间去研究研究,看什么时候能在将来的Framework中看到自己提交的代码,那是多么愉悦的事情啊,多谢了github这个分布式版本管理,我们就可以修改提交了,审核过不过无所谓,毕竟提交过,哈哈。如果有一天能审核过,那可以面试的时候或者跟猿们聊天的时候,多BB啊。

  一写就到了23:30了,明天还要上班,收笔把,还准备把反射出的不同版本的String和StringBuilder的代码贴出来的,打住了,身体也很重要。

Demo下载

源码下载

本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。

文章是哥(mephisto)写的,SourceLink

不同Framework下StringBuilder和String的性能对比,及不同Framework性能比(附Demo)的更多相关文章

  1. StringBuilder和string.Format性能对比

    本文由博主(YinaPan)原创,转载请注明出处:http://www.cnblogs.com/YinaPan/p/sbformat.html StringBuilder的性能优于string.For ...

  2. 【智能合约】编写复杂业务场景下的智能合约——可升级的智能合约设计模式(附Demo)

    智能合约的现状 以太坊在区块链上实现了智能合约的概念,用于:同质化通证发行(ERC-20).众筹.投票.存证取证等等,共同点是:合约逻辑简单,只是业务流程中的关键节点,而非整个业务流程.而智能合约想解 ...

  3. 简单对比一下不同Windows操作系统在相同硬件配置的情况下浏览器js引擎的性能

    最近部门进行Windows客户端的测试产品单点性能, 感觉不在通的windows版本以及浏览器内核的情况下性能可能有差异, 也一直没有找到一个比较好的对比工具, 今天用chrome的控制台简单测试了下 ...

  4. java String、String.concat和StringBuilder性能对比

    看到网上有人已经做过对比,并且贴出了代码,然后我运行了之后发现跟我分析的结论差距很大.发现他的代码有个问题,UUID.randomUUID() 首次调用耗时会很高,这个耗时被计算给了String,这对 ...

  5. [读书笔记]C#学习笔记八:StringBuilder与String详解及参数传递问题剖析

    前言 上次在公司开会时有同事分享windebug的知识, 拿的是string字符串Concat拼接 然后用while(true){}死循环的Demo来讲解.其中有提及string操作大量字符串效率低下 ...

  6. .Net Framework下对Dapper二次封装迁移到.Net Core2.0遇到的问题以及对Dapper的封装介绍

    今天成功把.Net Framework下使用Dapper进行封装的ORM成功迁移到.Net Core 2.0上,在迁移的过程中也遇到一些很有意思的问题,值得和大家分享一下.下面我会还原迁移的每一个过程 ...

  7. Java中String连接性能的分析【转】

    [转]http://www.blogjava.net/javagrass/archive/2010/01/24/310650.html 总结:如果String的数量小于4(不含4),使用String. ...

  8. StringBuilder和String的区别

      使用   StringBuilder 语言 C# String   对象是不可改变的.每次使用   System.String   类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为 ...

  9. Java中String连接性能的分析

    总结:如果String的数量小于4(不含4),使用String.concat()来连接String,否则首先计算最终结果的长度,再用该长度来创建一个StringBuilder,最后使用这个String ...

随机推荐

  1. 【Java每日一题】20161114

    package Nov2016; import java.io.Serializable; // V1.0版 public class Ques1114 implements Serializable ...

  2. 根据商品名称、价格区间检索商品的SQL语句

    如果名称和价格为空会检索出所有的数据 select * from TblProduct where (@proName='' or chvProName like '%'+@proName+'%') ...

  3. Spring发展历程总结

    目前很多公司的架构,从Struts2迁移到了SpringMVC.你有想过为什么不使用Servlet+JSP来构建Java web项目,而是采用SpringMVC呢? 既然这样,我们从源头说起.Stru ...

  4. 《Java4android》视频学习笔记——面向对象的应用(一)

    ---恢复内容开始--- 有一台HP打印机需要一个程序来实现开机,打印,关机这三个功能 class HPprinter { void open(){ System.out.println(" ...

  5. rabbitmq qos prefetch count的设置与作用

    因为原来使用了MQ作为rpc机制,随着客户交易量越来越大,很多服务器推送行情的压力很大,最近打算重写为批量模式,又重新看了下qos和prefetch设置的作用以确定优化的具体细节. 消费者在开启ack ...

  6. 当子查询碰上NULL

    情景: 现在有如图两个表,boy和girl,对应着Boy和Girl两个bean,有共同字段id.name,另外boy还有个外键grilfriend(指向girl的id) 现在要查询所有的Boy,如果有 ...

  7. Spring4学习笔记 - Bean的生命周期

    1 Spring IOC 容器对 Bean 的生命周期进行管理的过程: 1)通过构造器或工厂方法创建 Bean 实例 2)为 Bean 的属性设置值和对其他 Bean 的引用 3)调用 Bean 的初 ...

  8. Code First :使用Entity. Framework编程(1) ----转发 收藏

    这个是在学习EF CodeFirst时发现的,对于初学者还是不错的.果断转发,方便自己以后查阅和学习. 对于学习Code First 这个教程讲解的还是很详细. 第一章:欢迎来到Code First ...

  9. Photoshop如何实现UI自动切图?

    切图严格来说并不是UI设计师的工作, 而是前端工程师的工作,指的是将UI设计师的设计(大部分为photoshop创建的PSD文件)转化为界面(网页或窗体等)所需要资源的过程.切图是衔接UI设计和应用程 ...

  10. 使用nodejs+express+socketio+mysql搭建聊天室

    使用nodejs+express+socketio+mysql搭建聊天室 nodejs相关的资料已经很多了,我也是学习中吧,于是把socket的教程看了下,学着做了个聊天室,然后加入简单的操作mysq ...