请大家也试试这个Performance Quiz吧

园子里首页上基本都是些博主bala bala跟大家分享经验的文章,我来个换个话题,希望大家能喜欢。

这个问题其实是Rico Mariani零四年发布在他blog中的一个非常棒的帖子,最终演化成了一个系列。(可能有人要问Rico Mariani是谁,嗯,基本上没有人比他更有资格谈.net performance了),我在这里发的其实就是此系列的第一篇。

考虑下面三种选择

 sw.WriteLine(subject + "" + message);

.

sw.WriteLine("{0}: {1}", subject, message);

sw.Write(subject);
sw.Write(
"");
sw.WriteLine(message);

请回答下面的问题:

Q1. 哪种选择的性能最好?
Q2: 你能分别说明每种选择的内存分配情况吗?
Q3: 哪种选择会是performance team推荐的,为什么?
Q4: 什么特殊的因素会影响上面推荐的选择?
Q5: 在回答问题时,你需要对sw做哪些假设?

我也模仿下ricom,先不在这说答案和给出他blog的链接了,大家可以仔细想想,踊跃发言哈。

_____________________________________________________________________________________

谢谢大家的和发言,下面是Rico给出的答案,大家看看和自己想的一样不一样呢。(提示,rico的分析很长,但后面可能会帮助很多人纠正一些认识上的误区,所在要耐心看哦,这个是它的原文链接,感兴趣的可以去看看原文click here

Q1. 哪种选择的性能最好?

  1. 唯一可能确定的是#2的性能比#1性能差
  2. 如果有输出缓冲(buffer)的话,#3的性能最好
  3. 相反,如果没有输出缓冲的话,#1的性能最好 

Q2: 你能分别说明每种选择的内存分配情况吗?

  1. 一次连结(concat)操作,一个临时string对象,总共两次分配。
  2. 多次内存分配,包括string builder, underlying string buffer等。
  3. 一次。

Q3: 哪种选择会是performance team推荐的,为什么?

  1. #2会是CLR Performance Architects推荐的,虽然它性能最差,但直观而且易于维护。

Q4: 什么特殊的因素会影响上面推荐的选择?

  1. Specific measurements indicating that the code path had become a hotspot. (不好意思,我不知道code path应该怎么说,所以还是贴原句吧)

Q5: 在回答问题时,你需要对sw做哪些假设?

  1. stream没有额外的行为并且是有输出缓冲的。如果不是这样的话,1,2,3的语法就会有显著的区别并且可能性能差别会很大。
Rico用CLRProfiler对下面的程序进行了分析并进行了说明。
分析用程序
其结果如下:(具体的结果也可以去看他的blog
Option1: 4 calls, 2 allocations, for 94 bytes
static void Test.Test::Test1()
static String System.String::Concat(String,String,String)
     System.String(
48 bytes)
void System.IO.TextWrite::WriteLine(String)
     System.Char[] (
46 bytes)
     
void System.String.CopyTo(int32,wchar[], int32, int32)
     
void System.IO.StreamWriter::Write(wchar[], int32, int32)

说明:
  1. 只有一次连结操作(Concat),所以也只有一次为temp string分配内存。
  2. WriteLine方法并没有使用string builder对输出进行formatting.当参数只有一个时,WriteLine方法不会进行formatting.
  3. 当对单个参数 string调用WriteLine时,其实会将string转换成 char[]并在后面加上换行符。
  4. 转换后的char[]再加上换行符的总长度要小于原string,这是因为没有了string object overhead并且可能去掉了string终止符.
Option2: 30 function calls. 5 allocations. 184 bytes allocated (结果有些出乎意料吧?)
Option2 分析结果
说明:
  1. 第一次分配把两个固定的参数放至同一个object array中,以便WriteLine使用同一path.
  2. 第二次分配创建string builder来进行formating,只有string builder可以进行formatting.
  3. 第三次是分配用于初始化string buidler的buffer.
  4. 第四次将用于WriteLine输出的格式化好的string转换成char[]
  5. char[]后面加上换行符。
Option3: 7 function calls. 1 allocation. 32 bytes allocated
static void Test.Test::Test3()
     
void System.IO.StreamWriter::Write(String)
          
void System.String::CopyTo(int32, wchar[], int32, int32)
     
void System.IO.StreamWriter::Write(String)
          
void System.String::CopyTo(int32, wchar[], int32, int32)
     
void System.IO.StreamWriter::WriteLine(String)
          System.Char[] (
32 bytes)
          
void System.String::CopyTo(int32, wchar[], int32, int32)
          
void System.IO.StreamWriter::Write(wchar[], int32, int32)
同Option1,无formatting,只创建了一个string用于WriteLine.

读完的朋友感觉怎么样,没想到小小一行平时常见的代码里面的竟包含这么多东西吧。主要总结如下:
  1. 只有一个参数时,WriteLine不会进行formatting.
  2. 很多人认为WriteLine方面MS会做特别的优化处理,其实是没有,我们也看到了首先要转换成char[]然后再加上换行符。
posted @ 2007-10-18 00:24  芭蕉  阅读(2476)  评论(26编辑  收藏  举报