Performance considerations for strings in C# [1]
C# 字符串性能说想
Written By Dr Herbie [2]
Translated By Allen Lee
Reviewed By Teddy Tam & Allen Lee [3]
Introduction
你在代码中处理字符串的方法可能会对性能产生令人吃惊的影响。在本文中,我需要考虑两个由于使用字符串而产生的问题:临时字符串变量的使用和字符串连接。
Background
每个项目都有需要你为其考虑编码标准的时候。使用 FxCop 是一个好的开始。我最喜爱的一组 FxCop 规则是“性能”那组。
于是,我就用 FxCop 来检查我的项目并发现一系列的字符串问题。我必须承认一件事:我经常遇到与 C# 的不可变(immutable)的字符串有关的问题。当我看到 myString.ToUpper() 时,我经常都会忘记它并不是改变 myString 的内容而是返回一整个全新的字符串(这是由于 C# 中字符串是不可变的)。
我对代码进行一番修正以便去掉 FxCop 的警告,接着我就发现代码的确比之前快了。我决定开展调查,而最终我会写出上面那些测试的代码的。
Using the code
测试的代码很简单。一个控制台程序调用四个测试方法,其中每个方法执行一种字符串处理例程 1000 次(整个执行时间已经足够长以便看出其中的性能差别了)。
这四个测试方法被分成两组,每组两个。第一组比较两个方法,它们用于非大小写敏感(case-insensitive)的字符串比较。
String Comparison and Temporary String Creation
第一个测试例程是一个蹩脚的非大小写敏感的字符串比较。用于比较的例程的代码是:
staticboolBadCompare(stringstringA,stringstringB)
{
return(stringA.ToUpper()==stringB.ToUpper());
}
对于这段代码,FxCop 给出如下的建议:
"StringCompareTest.BadCompare(String, String):Boolean calls String.op_Equality(String, String):Boolean after converting 'stack1', a local, to upper or lowercase. If possible, eliminate the string creation and call the overload of String.Compare that performs a case-insensitive comparison."
这项建议的意思是每次对 ToUpper() 的调用都会创造一个临时字符串,而这个临时字符串是由垃圾收集器来创建和管理的。这需要额外的时间和使用更多的内存。 String.Compare 方法(相对来说)更加高效。
第二个测试例程使用 String.Compare :
staticboolGoodCompare(stringstringA,stringstringB)
{
return(string.Compare(stringA,stringB,true,System.Globalization.CultureInfo.CurrentCulture)==0);
}
这个方法防止多余的临时字符串的创建。
根据 nprof 的分析结果 , GoodCompare 的执行时间只占代码总执行时间的 1.69%, 而 BadCompare 的执行时间则占总执行时间的 5.50% 。
因此 String.Compare 方法比 ToUpper 方法快了三倍有余。如果你的代码您执行了很多字符串的比较(尤其是在循环里面执行),使用 String.Compare 能(使你的代码在性能上)有较大的改善。
String Concatenation inside a loop
最后那对测试例程设想字符串的连接是在一个循环里面进行的。
“蹩脚”的测试例程的代码如下:
staticstringBadConcatenate(string[]items)
{
stringstrRet=string.Empty;
foreach(stringiteminitems)
{
strRet+=item;
}
returnstrRet;
}
当 FxCop 看到这段代码,它就会很愤怒,甚至用红色标记这项被破的规条! FxCop 这样说道:
"Change StringCompareTest.BadConcatenate(String[]):String to use StringBuilder instead of String.Concat or +="
“优良”的测试例程的代码如下:
staticstringGoodConcatenate(string[]items)
{
System.Text.StringBuilderbuilder=newSystem.Text.StringBuilder();
foreach(stringiteminitems)
{
builder.Append(item);
}
returnbuilder.ToString();
}
这段代码几乎被用作展示 System.Text.StringBuilder 的用法的首选例子。蹩脚的代码的问题是创建了过多的临时字符串。由于字符串的不可变特性,连接操作符(+=)实际上用原来那两个字符串来创建一个新的字符串,然后把原来的字符串实例指向这个新的字符串。
但是,依据 nprof 来研究代码性能,我们发现运行 BadConcatenate 只需总执行时间的 5.67% ,而 GoodConcatenate 则是 22.09% 。也就是说:
使用 StringBuilder 耗费的时间几乎是简单的字符串连接的四倍!
为什么呢?
部分原因在于这个测试的设计——连接例程仅仅连接了十个简短的字符串。 StringBuilder 是一个比简单的不可变的字符串类更复杂的类,因此创建一个 StringBuilder 比起进行十个简单的字符串连接在性能上是昂贵很多的。
我重复地做不同数目的字符串连接的测试,并且发现以下结果:
注意:这里所显示的数值是测试例程的执行时间占总执行时间的百分比(%)。 GoodConcatenate 实际上并没有快很多,但与 BadConcatenate 比却相对地快了。
因此, StringBuilder 通常只有在你要连接的字符串数目超过 600 时才会显示出真正的性能优势。
当然,另外一个使用 StringBuilder 的原因就是是内存的分配。使用 CLRProfiler 生成下面这个连接 100 个简单字符串时内存使用情况的时序图:
标记为“A”的区域显示了 BadConcatenate 在内存分配和释放上的效果。被分配内存的最大值迅速增加,并伴有大数量的垃圾收集的发生(该区域有大约 215 次垃圾收集)。
紧随在“A”区后面的区域显示了 GoodConcatenate 的内存轮廓。被分配内存的最大值增量较少,且伴随着非常少的垃圾收集(该区域有大致 60 次垃圾收集)。
所以在某些情况下使用 StringBuilder 类并不会(使你的代码运行得)更快 , 但它对垃圾收集器是友好的。
Conclusions
使用 String.Compare 方法进行非大小写敏感的字符串比较。这样更快。而且代码优雅和简单。
仅当你在一个循环里进行超过 600 次的字符串连接时,使用 StringBuilder 来获得更好的速度。这里需要提醒的是,你所处理的字符串的长度也会影响最终的速度,同样会影响垃圾收集器的效果,所以你应该根据你实际的代码具体问题具体分析。
Points of Interest
令我惊讶的是,在真实世界运用正确的代码字符串操作方法的还是很不同(虽然我们已在当前的项目中进行了很多字符串的比较和连接)。
FxCop 的性能规则是发现潜在低性能代码的好起点,并能指导你进行一些简易修正来改善代码性能。这里所讨论的两个问题都被 FxCop 标记为“NON-BREAKING”,这是指改动不应破坏依赖于被改动代码的代码。认为为改善性能而做的改动都是“NON-BREAKING”则是没头脑的想法。
Further Considerations By Allen Lee
使用 StringBuilder 来处理字符串的连接应该是绝大多数 .NET 开发人员的共识了。但你有否曾经怀疑过这一经验原则的适用性是否真如想象中那么广泛呢?读过本文后,或许你已经意识到这是个适度的问题。对小规模的字符串连接使用 StringBuilder 所带来的改善根本不足以抵偿因 StringBuilder 本身的复杂性所产生的开销;只有当连接规模达到临界规模,两者才能相互抵偿从而达至平衡。
对于实际的代码,一个可供使用的临界规模值可能是必需的,尤其是在受限系统上进行开发。你可能因为对影响临界规模的因素有所了解而怀疑作者在这里所给出的数字。或许本文用于测试的设计显得有点简单以至于未必能使更多的人信服,但你的确透过本文了解到 StringBuilder 并不是任何情况都适用的。由于影响临界规模的因素总有可能发生变化,你不可能找到一个对任何情况都适用的确定的临界规模值。你应该为你的代码量身订造一个,并随时做好调整的准备(因为变化总是存在的),只要你真的那么在意这方面的性能影响。作为一个开始,你可以以作者在本文所提到的那个数字作为一个参照基础,并就具体的情况进行微调,直到你满意为止。
History
- 2005-06-03:完成本文翻译的初稿。
- 2005-06-05:在 Teddy Tam 的协助下完成本文翻译的三次审校。
- 2005-06-07:确定本文的最终译稿并完成后期加工制作。
-
[1] 版权声明:本译文仅供学习研究之用,其中所有来自原文(点击这里查看原文)的内容(包括文字、数据和图表等)的版权归原作者所有。未经许可不得以任何形式转载其中的部分或全部。
-
[2] 关于本文的作者 Dr Herbie :点击这里查看作者的其他文章以及作者的简介。
-
[3] 非常感谢 Teddy Tam,他在本文的整个翻译过程中给了我很大的支持和帮助,并就本文的翻译提供了很多专业的意见!
分享到:
相关推荐
首先,你需要读取文本文件或数据库中的数据,然后使用LINQ查询来处理字符串,例如,去除标点符号、停用词(如“的”、“是”、“和”等常见词汇)并转换为小写,以便进行比较。 接下来,为了将这些数据转化为可视化...
5. **配置文件(Configuration Files,如app.config/web.config)**:用于存储应用程序的配置信息,如数据库连接字符串、服务端口等。 6. **引用(References)**:项目可能需要引用其他的DLL文件,这些文件包含了...
- 对于16进制字符串,可以使用`Convert.ToInt32(string, 16)`将16进制字符串转换为整数,再进一步转换为ASCII码。 在进行CAN报文解析时,测试人员可能需要将接收到的16进制报文数据转换为ASCII字符串,以检查其中的...
本篇文章将根据提供的代码示例,详细介绍如何通过WebService接口接收XML格式的数据以及字符串类型的数据,并对相关知识点进行深入剖析。 #### 二、接收XML数据 首先,我们来看一下如何通过WebService接口接收XML...
4. **资源文件(Resource Files)**:如图片、配置文件、数据库连接字符串等,用于增强程序的功能和用户体验。 5. **配置文件(Configuration Files)**:如app.config或web.config,用于存储应用程序的配置信息。 6...
答案:.NET 控制台应用程序的入口点方法是 Main 方法,建议为命令行参数使用可选的字符串数组,返回类型是 int。 知识点 9:如何寻找关于 C# 关键字的帮助? 答案:微软文档网站,具体来说,有关 C# 关键字的文档...
例如,TextBox控件可以与字符串变量绑定,显示或接收用户输入的数据。 5. **设计模式**:虽然C#窗体应用程序主要涉及UI设计,但也可以应用设计模式,如MVC(模型-视图-控制器)模式,将业务逻辑、数据和用户界面...
5. **配置文件(Configuration Files)**:如"MyProject.config",用于存储应用的配置信息,如数据库连接字符串、服务器地址等。 6. **库和框架引用(Library and Framework References)**:项目可能会引用其他DLL...
6. **Configuration Files**:如app.config或web.config,存储应用程序的配置信息,如连接字符串、设置等。 7. **Documentation**:可能包括设计文档、用户手册等,解释系统的架构和使用方法。 综上所述,这个项目...
5. **Config Files(配置文件)**:如Web.config,包含了应用程序的配置信息,如连接字符串、路由规则等。 6. **View Templates(视图模板)**:.aspx或.cshtml文件,用于构建网站的前端界面。 7. **CSS/JavaScript ...
4. **资源文件(Resource Files)**:可能包括配置文件、数据库连接字符串或其他外部数据源的引用。 通过学习这些源码,你可以了解如何使用C#创建基本工作流,如顺序流、并行流和决策流。同时,你还可以学习如何...
4. **配置文件(Configuration Files)**:如 `web.config`,用于存储应用程序的配置信息,如数据库连接字符串、路由设置等。 5. **静态资源(Static Assets)**:如CSS样式表、JavaScript文件和图片,用于美化和...
- **串和数组**: 讨论字符串处理和数组操作的相关算法。 - **树型结构**: 涵盖二叉树、平衡树等多种树结构的实现方式。 - **图结构**: 探讨图的基本概念及其应用,如最短路径算法等。 #### 4. .NET框架中的数据结构...
【标题】基于C#的仓库管理系统源码 在IT领域,C#是一种广泛使用的编程语言,尤其在开发Windows应用程序和Web应用程序时。...对于想要提升C#技能或了解企业级应用开发的人来说,这是一个宝贵的资源。
5. **配置文件(Configuration Files)**: 如app.config或web.config,用于存储应用程序的配置信息,如数据库连接字符串、日志设置等。 6. **数据库脚本文件(Database Scripts)**: SQL 文件,用于创建和初始化...
在开发OA系统时,C# 2005提供了良好的性能和稳定性,同时其语法简洁,易于学习,适合快速开发大型企业级应用。 二、OA系统核心功能模块 1. **用户管理**:OA系统通常包含用户注册、登录、权限分配等功能。在C# ...
5. **数据库文件或连接字符串**:可能包含数据库脚本(.sql)、数据库配置文件或数据库连接字符串,用于存储和访问学生数据。 6. **资源文件(Resource Files)**:如图片、CSS样式表和JavaScript文件,用于页面的...
【标题】: "基于C#的计算机教学网站源码" 是一个用于开发和学习的项目,它使用C#编程语言构建了一个在线教育平台。这个源码可以为学习者...同时,对于想要从事计算机教学网站开发的人来说,这是一个宝贵的参考资料。
- 第2章至第6章分别探讨了线性表、栈和队列、字符串和数组、树形结构和图结构等常用数据结构及其应用。 - 特别强调了.NET框架中对应的高级数据结构实现。 - **算法**: - 第7章和第8章重点讨论排序和查找算法,并...
总的来说,分析这个"C#语言编写的网站.zip",你需要理解ASP.NET MVC架构,掌握C#语言,熟悉.NET框架,并对Web开发的最佳实践有一定了解。同时,通过阅读和运行代码,你可以深入学习到实际项目开发中的各种技术应用和...