2008年10月13日星期一

IIS7 地址重写模块(ASP.NET and the new IIS7 Rewrite Module)

在上一年,我注意到这里有11个方式能进入到我的blog。准备的说是11个不同的url,但它并不能帮助我在搜索引擎中提高排名。
在最新版的ISAPI_Rewrite和Apache's standard mod_rewrite模块中都使用了分离的configuration 文件或.htaccess文件。
下面是我.htaccess文件的一部分,它确认所以进来的URLs都结束于最后的链接http://www.hanselman.com/blog/:

RewriteRule /blog/default\.aspx http\://www.hanselman.com/blog/ [I,RP] 
RewriteCond Host: ^hanselman\.com
RewriteRule (.*) http\://www.hanselman.com$1 [I,RP]

RewriteCond Host: ^computerzen\.com
RewriteRule (.*) http\://www.hanselman.com$1 [I,RP]

RewriteCond Host: ^www.computerzen\.com
RewriteRule (.*) http\://www.hanselman.com/blog/ [I,RP]
在你安装了IIS7 Rewrite module后,你能以两个方式输入url规则。最好的方式是真接的导入他们。注意这种输入文件的规则必须是被mod_rewrite语法所知道的规则。它并不完全的支持ISAPI_Rewrite。例如Host:[I]不被支持在这次的发布的版本中,但是我希望在最终的RTW版本能支持它们。如果你有ISAPI_Rewrite规则,你可以手动的转换整理它们。
例如,在rule输入界面里,我替换ISAPI_Rewrite指令“Host:"用"&{HTTP_HOST}代替,[I]用[NC](不区分大小写)等等。
image
这是一种有用的导入规则的方法,但是处理起来有时候比较困难。另外还有一种添加规则的方法
Add rule(s)
这是一种非常简单的方法,通过提供了一个友好的交互式窗口,用于创建应用程序URL和你想要的URL之间的映射,如下图所示
Add rules to enable user friendly URLs (2)

2008年10月12日星期日

关于在IIS6.0创建webSites的最佳做法(Best practices for creating websites in IIS6.0)

每一次我创建一个IIS网站,我总要做一些步骤,我考虑这些步骤是为了网站更好的性能,更加易于维护,以及具有伸缩性。下面是我做的步骤:
1. 对每一个web应用程序创建一个可分离的应用程序池(application pool)
我总是创建 一个分离的application pool为每一个应用程序,因为这样我可以为应该用程序的回收选择不同的计划时间。一些通信压力大的websites有一个长一些的回收计划时间,一些通信小的webSites能一个短点的回收计划时间。此外,而且我能够为这些app pool选择不同的进程数量。这些使用web garden模式的应用程序得益于多个进程,另外在进程中使用了session以及memory cache的进程则有一个单一的进程服务于它的app pool中。所以将所有的应用程放在DefaultAppPool 下不能给我一个弹性去控制每一个网站。
你创建许多的app pool,那么你的应用程序就有更多可用的ASP.NET线程。每个w3wp.exe都有它自己的线程池(thread pool)。因此,如果一些应该程序被特定的w3wp.exe阻塞着,其它的应用程充也能够开开心心的运行在他们分离下app pool的w3wp.exe中。每一个app pool都 管理着他们自己的w3wp.exe实例。所以,我的首要规则是:我总是创建一个新的app pool为一个新的web应用程序并且以其网站domain命名,或者更加有意义的名字。例如,你创建一个网站叫alzabir.com,则可以将app pool命令为alzabir.com 。
2.禁止DefaultAppPool,以免你将网站加到DefaultAppPool中去而犯错误。
3.设置IIS的一些日志属性。
4.设置IIS的错误页(404),以及打一个缓存cache 。
5.设置IIS6.0的Gzip compression.
6.明确设置你的网站的asp.net的版本。
具体操作如下所示:
如下二图所示:首先你创建一个新的app pool,然后你创建一个新的webSite或虚拟目录。打开Properties -> Home Directory tab->Select the new app pool.注意将DefaultApplicationPool禁止。

image
image

接下来,你应该映射正确的host headers到你的网站中去。怎么去做呢?打开WebSite并且点击“Advanced”按钮。加上两个映射地址domain.com和www.domain.com 。注意,许多时间,人们总忘记去映射domain.com。然后许多访问者都跳过类型www的前缀,结果得到页面无法访问的情况。操作如下图所示:

image

再接下来配置一些日志信息:

image

这样很方便得可以去分析网站。如果你想去测量你的宽带消耗对于特定的网站,你应该去勾选Bytes Sent ;如果你想去测量不同页面的执行时间并且找出运行慢的网页,你应该去勾选 Time Taken;如果你想去测量特殊的访问者和回访者,你应该去勾选Cookie。如果你想去知道进入你网站的前一个网站地址或者发给你的一些搜索引擎地址,你应该去勾选Referer。接下来你就可以使用分析式具去分析了,例如,使用open source AWStats.
但是,如是你使用Google Analytics或者其它一些分析工具,你应该将它们关闭,特别是Cookie和Referer,因为它们在日志中占有非常多的空间。如果你使用ASP.NET Forms Authentication并且是一个中等通信规模的网站,则来自于每一个请求的世大的cookie每一周将产生GB(gigabytes)日志数量的数据。
image

然后,我加了一个Default.aspx作为一个默认的内容页。当用户访问网站没有任何.aspx页同名字的时候,便如alzbir.com,他们得到一个default.aspx页面(如上图所示)。

image

再接一来,我要做以下事情(如上图所示):
1) 打开内容过期时间。这将使静态文件,例如images,javascripts,css文件不用从服务器上下载一遍又一遍。这一个设置将明显的提高你的网站性能。
2) 移除X-Powered-by:ASP.NET header。你实在是不需要它,除非你想附加一个Visual Studio Remote Debugger到你的IIS,否则,它将在每一个response中发送21bytes到你的客户端。
3) 加上一个"From" header并且设置它的服务器名称。我做这一步在每一个webserver,并指定不同的名字。它很清楚的可以看到来自那一个的服务品的requests正在被工作。当你想去机检测负载平衡的时候,它很楚的可以知道一个指定的服务器是否正在发送requests .

image

我设置一个404 控制一些aspx,这样我能显示一个友好的错误信息。但是另外一个原因是去使用这个客户端的映射来实现可扩展性的URL。具体请看这篇文章

image

然后确定你的ASP。NET2.0,3.0和3.5的网站设置ASP.NET2.0。
最后,我重复的提醒你必须去打开IIS6.0 GZIP compressionThis turns on the Volkswagen V8 engine that is built into IIS to make your site screaming fast

IE8 Beta2 AJAX 的更新篇之XDR(二)(IE8 Beta2 Hand-on Lab-XDR)

Croos-domain Request("XDR")
一.背景:
Web浏览器都有一个安全方针被叫着the same-site origin policy,这一原则阻止了跨域访问数据。下面的图显示了一个站点使用IE7或更高版本在不同域之间的访问。(图来自于IE8 beta2 Hand-on Lab)







而在IE8 beta2中,Web页面通过使用xDomainRequest对象代替server-to-server的请求来实现跨域请求。如下图所示:









XDRs要求Web page和server之间遵循一种规定。你能初始化一个跨域的请求通过创建一个xDomainRequest对象并且向一定特定的域建立一个连接。如果页面收到一个Access-Control-Allow-Origin:*的header的responds,表示完成了一个连接。例如:一个服务器端的ASP页面包含 下面的response header:

注意:为了保护用户的数据,跨域请求是匿名的,这意味着服务器端不能简单的找出是谁request data.结果,你仅仅能request和respond一些不是敏感的或者个人能确认的跨域数据。
二.API Documentation
下面的javascript代码片段介绍了xDomainRequest对象,以及它的事件,属性。在MSDN中有更详细的介绍,地址(http://msdn.microsoft.com/en-us/library/cc288060(vs.85).aspx
//创建一个新的XDR Object
xdr = new XDomainRequest();
//创建一个the request请求不能完成的错误方法
xdr.onerror = alert_error;
//请求时间已到的事件
xdr.ontimeout = alert_timeout;
//对象已经连接,正在返回数据的事件
xdr.onprogress = alert_progress;
//对象完成的方法
xdr.onload = alert_loaded;
//设定一个请求的时僮
xdr.timeout = timeout;
//在一个请求中得到content-type header
var content_type = xdr.contentType
//得到response的text
var response = xdr.responseText;
//创建一个跨域连接请求
xdr.open("get",url);
//发送请求
xdr.send();
//取消一个请求
xdr.abort();
三.代码例子
注:所有例子都来源于IE Beta2 Hand-on Lab!

2008年10月11日星期六

IE8 Beta2 AJAX 的更新(一)(IE8 Beta2 Hand-on Lab)

Windows Internet Explorer 8 Beta2的一个主要目标是去提高开发者的开发效率,IE8开发人员通过提供跨浏览器以及一些强大的应用程序API去达成这个目标。
IE8 beta2 提供了一个简单但是强大的跨浏览器,跨页面,以及server之间的交互的应用程序模块给AJAX的开发者使用。你能够使用它们建立一个快速的并且更加实用的页面,给用户一个更好的体验。另外,IE8 beta2 APIs 是基于 W3C(World Wide Web Consortium)HTML5.0  或者 WWG(Web Applications Working Group)标准的。
下面我将分别介绍新的AJAX特性,它将帮你应用这些新的技术到你的网站中去。下面是新的特性的简介。
1. 跨域通信是ajax开发和混合应用程序的一个主要部分。IE8 Beat2提供了两个安全和简单的跨域的特性用于两个不同域之间的通信。
1)XDomainRequest(Cross-domain Request):开发者可以创建一个跨网站的数据集合脚本。它与XMLHttpRequest对象差不多,但是却拥有更简单的程序模式,这种请求被叫做xDomainRequest,它以更简单的方式以一种匿名的requests给第三方的支持XDR的网站。只需要仅仅的三行代码就能帮你实现一个基本的跨网站的请求。这种请求是简单,安全并且是快速的。
2) XDM(Cross-document Messageing):IE8 APIs中提供了一个简单的安全,标准的方法用于在来自两个不同域通过IFRAMEs之间的documents相互通信。
2. XMLHttpRequest Enhancements:XMLHttprequst提升给了你一个对于提高性能和管理你页面状态的一个更好的控制。它包括了一个timeout属性,这个属性能帮助你在需要的时候取消当前的request,允许开发者管理更好的请求。
3.Ajax Navigations:在ajax项目中,浏览器的向前,向后按钮一直是开发者的心病,需要额外的代码或框构去实行,现在,IE8 beta2通过一个简单的方法就在ajax中实现向前向后按钮。它使用设定window.location.hash的值更新浏览器的组件跟Address bar一样,在页面中,引发一个event去关注组件并且创建一个返回按钮的事件和浏览器历史。
4. DOM Storage:这是一个通过key/value保存和获取数据的方法。它允许页面去在机器上缓存一个text,通过提供一个对每一个cache数据的访问而减少网络潜在的影响。它的一些革新就是围绕着网络连接和没有连接的情况。例如:使用Dom Storage在与一个新的网络连接联系在一起的event能够cache数据,当event发现计算机掉线的时候。另外,在客户端保存数据,可以减少多次发现一样的数据到客户端。
5.Connectivity events:它允许网站去检查当用户连接到网络并且收到连接改变的通知。另外,每一个host在宽带的连接情况下允许6个连接和一个脚本属性使能够达到下载的平衡而大大提高了浏览器的性能。
6.ToStaticHtml,to JSON,and FromJSON:当使用xDomainRequest或者Cross-document Mesaging后你应该做什么呢?在今天日益提高的脚本注入(script injection)和跨站脚本攻击(XSS-Cross-site Scripting attacks,IE8 Security可参考Comprehensive Protection文章),ToStaticHTML提供了一个强大的方法对你的String去清除潜在的危险内容。
以上只是IE8 beta2中ajax future的简介,针对每个详细的介绍及例子我会后续的文章中给出,请大家关注!谢谢!

2008年10月10日星期五

XmlDocument与xelement性能(XMLDOCUMENT VS XELEMENT PERFORMANCE)

我已经使用XElement有一段时间了,下面我做了一些性能的测试,并指出在xmlDocuemnt和xelement之间的不同。
首先,XElement是.NET Framework3.5的一部分,它被使用在xml to linq,并且位于System.xml.linq命名空间下。这个class在linq方面得到了很好的使用。xElement.Nodes和xElement.Attribues返回了一个IEnumerable,这个接口很容易的被使用于nodes的访问。当然你也可以使用Lambda expressions操作它们。更多的信息请参考http//msdn.microsoft.com/en-us/library/bb487098.aspx
在下面的例子中,我创建了两个static方法,一个使用xmlDocument,一个使用xElement去生成一个XML,通过循环system assembly exported type构建一个巨大的xml ,并将其保存到Stream中去,下面是两段代码:
   1://Generates XML using XmlDocument
   2: internal static void GenerateXmlUsingXmlDocument() 
   3: {
   4:     MemoryStream ms =new MemoryStream();
   5:     XmlDocument xmlDoc = new XmlDocument();
   6:     xmlDoc.AppendChild(xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", "no"));
   7:     XmlElement assembliesNode = xmlDoc.CreateElement("Assemblies");
   8:     foreach (Type t in Assembly.GetAssembly(typeof(Object)).GetExportedTypes())
   9:     {
  10:         XmlElement assemblyNode = xmlDoc.CreateElement("Assembly");
  11:         XmlAttribute fullTypeName = xmlDoc.CreateAttribute("FullTypeName");
  12:         fullTypeName.Value = t.ToString();
  13:         XmlAttribute isInterfaceName = xmlDoc.CreateAttribute("IsInterface");
  14:         isInterfaceName.Value = t.IsInterface.ToString();
  15:         assemblyNode.Attributes.Append(fullTypeName);
  16:         assemblyNode.Attributes.Append(isInterfaceName);
  17:         assembliesNode.AppendChild(assemblyNode);
  18:     }
  19:     xmlDoc.AppendChild(assembliesNode);
  20:     xmlDoc.WriteContentTo(new XmlTextWriter(ms,System.Text.ASCIIEncoding.ASCII));
  21: }
  22:  
  23: //Generates XML using XElement
  24: internal static void GenerateXmlUsingXElement()
  25: {
  26:     MemoryStream ms = new MemoryStream();
  27:     XElement assembliesNode = new XElement("Assemblies",
  28:             from Type t in Assembly.GetAssembly(typeof(Object)).GetExportedTypes()
  29:             select new XElement("Assembly",
  30:                 new XAttribute("FullTypeName", t.ToString()),
  31:                 new XAttribute("IsInterface", t.IsInterface.ToString())));
  32:     
  33:     assembliesNode.Save(new XmlTextWriter(ms, System.Text.ASCIIEncoding.ASCII));
  34: }
你可以发现上面两个方法中的不同了吧,xElement使用 LINQ expressions生成xml,它代码简单明了。通过下面的代码,我重复的测试在每个方法中执行时间
1: Stopwatch sw = new Stopwatch();
   2: for (int index = 0; index <>
   3: {
   4:     sw.Reset(); sw.Start();
   5:     Program.GenerateXmlUsingXmlDocument();
   6:     sw.Stop();
   7:     Console.Write("Generation time using XmlDocument " +
   8:         "and XElement: " + sw.ElapsedMilliseconds);
   9:     sw.Reset(); sw.Start();
  10:     Program.GenerateXmlUsingXElement();
  11:     sw.Stop();
  12:     Console.WriteLine(" : " + sw.ElapsedMilliseconds);
  13:     //Forcing the Garbage Collector to run to make sure,
  14:     //We dispose of all the types we created on the
  15:     //Managed heap.
  16:     GC.Collect();
  17: }
  18: Console.ReadKey();间
从上面的代码中,你可以发现我循环50次去测试每一个方法,另外,在每个测试后,我都显视的调用了GC回收器去清理通过两个方法创建的对象。下面我显示测试的结果:
XmlDocumentXElement
在上面,你可以清楚的发现,在两个方法中create xml的不同。它们之间的执行时间相差了6到10倍。在ASP.NET applications 和Web Services 中以每毫秒计算犹为重要。还有一件事情提醒一下,xElement是 .NET 3.5中Ssytem.xml.linq.dll的一部分,但是它仍桀犬吠尧是以.NET 2.0 CLR运行的,因此,如果你还没有使用.NET 3.5,你可以 copy System.Xml.Linq.dll在你的应用程序下。但是,你会错过许用来自于.NET team的好的更新。
英文地址(引用):XMLDOCUMENT VS CELEMENT PERFORMANCE



异常的性能及抛出(Exception Throwing)

1. 抛出异常(Exception Throwing)
抛出异常在这篇文章里被定义为是对执行失败时给出的定义。执行失败在任何时候都引出了一个被设计好的程序不去做它应该做的事情。例如,如果打开一个文件的方法不能返回一个打开文件的操作给调用者,则它应该被设计成一个执行失败。
许多开发者可能已经很自然的去使用exceptions处理例如像除以0,以及为对象为null引用的过程。在framework中,expceptions被使用在复杂错误和逻辑错误中。首先,它很难去报告所有功能失败的手段,但是它被设计成对framework中所有公共方法通过抛出一个异常去报告方法的失败。
其实有各种各样的方法可以不使用异常处理,但大多数规结了两种,一种是返回一个错误的代码或者错误的模块不去执行并且返回一个错误的代码。性能的考虑在下面一节中讨论。作为一个API的设计者,我们不应该去猜测使用我们代码的开发者对我们的程序很熟悉,下面是异常的一些使用方法与规则:
1)不要返回一个错误代码。exceptions是在框架中报告错误的主要方法。
2)通过抛出异常报告执行失败。
3)  考虑终止进程。当你的程序遇到下一步执行不安全的时候,通过调用System.Environment.FailFast(.NET Framework 2.0 feature)代替抛出异常。
4) 不要在正常的控制流程中使用异常。除了系统错误,一般写代码的时候避免抛出异常。例如,在调用一个成员之前,你可以提供一个方式去检查。
ICollection collection = ...
if( !collection.IsReadOnly ){
collection.Add(additionalNumber);
}
被设计成执行其它成员的先决条件的成员被称为tester,实际工作的成员被称为doer.(在下性能的章节中有更多关于Tester-Doer Pattern的信息)。
5.  考虑性能的影响(在下面介绍)
6.  不用使用一公共的成员,它们为一个返回的值或out parameter返回异常。
7.  考虑使用异常bulder methods.它是在不同地方抛出一样异常的方法去避免代码的冗余。
class File{
string fileName;
public byte[] Read(int bytest){
if( !ReadFile(handle,bytes)){
throw NewFileIOException(...);
}
}
FileExceiption NewFileExction(...){
string description = //build localized string
return new FileExceipton(desciption);
}
}
1.2 异常和性能
在异常发生时候时候,它的性能会变慢。但是它也有可能获得好的性能当中止执行错误代码的时候。在下面我就介绍一下这两个情况:
1) 不要使用错误代码,因为异常引起了性能过慢
Tester-Doer模式
有时候,抛出异常的性能的成员能通过将其自身折成两个来提高性能,让我们来看看下面的例子:
Dictionary table = new Dictionary();
...
int value = table["key"];
如果the key不存在,则这个索引器将引出一个异常而引起一些性能问题。我们将其改成
Dictionary talbe = new Dictionary();
...
if( table.Contains("key") ){
int value = table["key"];
}
table成员使用了测试条件,在我们的例子中是Contains方法,这个被称作为'tester',下面一个用于操作的方法的成员就叫做Doer。这就是Tester-Doer 模式。考虑使用Tester-Doer模式去避免与异常有关的性能问题。
TryParse模式
对于极高性能要求的API,则一个更快的模式应该被使用。例如,DateTime有一个方法Parse方法去将日期转换为string,还定义了别外一个TryParse方法也是做同样的事情,但是两者的区别在于,前者失败的话会抛出一个异常,而后者失败的情况下返回一个false.
本人观点:
上面的观点来自于krzysztof cwalina的ExceptionThrowing,可能大家看的有得迷糊,翻译得不是很理想。望大家见谅。就我的理解,文章中提到几个重要的地方那就是,如果要使用抛出异常,尽量使用系统自带的。如果在程序中,尽量在可能出现异常的地方使用Tester-doea和Tryxxx方法去控制异常,毕竟程序性能是第一.
英文地址(引用):Exception Throwing
  参考地址:The Cost of Exceptions

2008年10月9日星期四

StringBuilder等字符连接的性能分析(Concatenating Strings Efficiently)

    许多开发者认为改善性能的途经之一是使用StringBuilder去连接strings,其实这有一定的误解!但幸运的是它有时候确实能改善性能!如下:
     1 .我们应该避免以下问题
using System; public class Test { static void Main() { DateTime start = DateTime.Now; string x = ""; for (int i=0; i < style="COLOR: black" class="String">"!"; } DateTime end = DateTime.Now; Console.WriteLine ("Time taken: {0}", end-start); } }
      在我比较快的笔记本电脑中,这段代码花费了我10秒钟。如果再翻倍 ,则它超过了1分钟(注:结果在.NET2.0 beta中轻微的要好些,但是这种改变不是很大)。这里真正的问题在于strings是不可变的,我们使用了+=而不是真正的意味着让runtime(运行时)去添加存在字符串到已经存在字符串的尾部。实际上,x  += "!" 就等于 x = x + "!".这种连接相当于重新创建了一个全新的string(并且为此分配了相相当大的内存),首先从原来已经存在的值的x中Copy所有的值,然后再把添加了!的值Copy过来。当这个string快速增长的时候,将数据copy的数量也在增加,这就是为什么我添加2倍循环的时候则时间花费不是原来的2倍,而是超过了!上面的代码明显的是低效率的,这时候stringbuilder就派上用场了!
2. StringBuilder解决方案
下面是一段与上面代码等价的程序,我们改用了stringBuilder,你会感觉到速度快了好多!
using System; using System.Text; public class Test { static void Main() { DateTime start = DateTime.Now; StringBuilder builder = new StringBuilder(); for (int i=0; i < style="COLOR: black" class="String">"!"); } string x = builder.ToString(); DateTime end = DateTime.Now; Console.WriteLine ("Time taken: {0}", end-start); } }

同样在我的笔记本电脑中,速度快了好多,我将循环提高了10倍(在第一程序中花了我10秒钟),而在这段程序中才花了30-40MS,而且粗略的看,这是时间的提升是线性的,也就是说我提高2倍的循环,它就花费2次的时间.它避免了不必要的copy(唯一的copy就是append中的字符串copy).StringBuilder维持了一个内部的缓冲区去添加这些string(实际上,内部的缓冲区也是一个string,这个string是不可变的,来源于一个公共的接口,而不是来源于mscorlib的内部)。我们能在改变上面的的代码使其更加具有效率就是通过给stringBuilder设定一个正确的缓冲区大小。这样它就会避免一些不必要的copy。
      3.我可以在任何地方都 使用stringBuilder???
       又回到我们上边的刚开始的话题了,这当然不是绝对的,看看下面的例子:
string name = firstName + " " + lastName; Person person = new Person (name);
     有些人写成这样:
 
// Bad code! Do not use! 
StringBuilder builder = new StringBuilder();
 builder.Append (firstName); 
builder.Append (" ");
 builder.Append (lastName); 
string name = builder.ToString(); 
Person person = new Person (name);
 现在,在更广泛的观点上,有人认为第二个版本比第一个版本效率要高一些,但它有可能不是非常有效率的,除非那段代码调用了非常非常多的数量,则它花在连接上的时间可能会小。而且为了第二个版本的代码那么少的效率而缺少 了第一段代码的可读性是一个bad idea。
但是,实际上第二段代码是低效率的比第一段代码。第一个版本的compiles时 调用了string.concat,像这样:
string name = String.Concat (firstName, " ", lastName);
Person person = new Person (name);
string.concat能够将许多的strings和对象连接到一起,它是简单而有效的。并且strign.concat有很多的重载
string.concat没有多余的copy.数据只copy一次到一个新的string,这个string刚刚好有一个正确的长度。
比较stringbuilder版本,它不知道要连接的字符串的缓冲区大小(因为我们没有告诉它),这就意味着
它必须copy比它实际需要还要大的缓冲区。更重要的是前一个方法我们只要调用一次string.concat就
可以将字符串连接在一起,而后面则多了几次中间结果的copy.
4.常量
当是几个常量进行的连接的时候,事情变得也不一样了,你是否会觉得string x= "hello" + "there"
编绎的时候也会调用string.concat,其实你错了,它实际上被编译成string x="hello there".编绎器
知道所有的部分都是常量,因为它在编绎的进候做连接,将全部的string存储在编绎的代码中。如果这时候
将其转换成stringbuilder,那么不管从内存上都是时间上来讲都是低效率的,而且缺少了代码可读性
5.规则
那么我们什么是用stringbuilder,什么时候用连接操作符呢?
1. 明确使用stringbuilder:当你在一个巨大的循坏中进行连接操作,并用你不确实你的循环次数的时候。
例如:每一次读一个文件的一个字符,如果这时候你用+=等于就是自杀!
2. 明确使用操作连接符:当你在一句话中能明确指定连接的时候(如果你有数组去连接,考虑调用string.concat或如果需要分隔符则调用string.join)
3. 不要担心将一个比较长的文字拆成多个部分,因为这样增加了易读性,并且不损坏性能
4. 如果你一些字符串要连接,并且想分成多个语句实现。这个方式的效率取决于你要连接的字符串的
数量,已经连接的先后。如果你认为这段代码是你程序中的一个性能瓶经,则应该在各种方法中找到一个平
衡点!
英文地址(引用):Concatenating Strings Efficiently