作为一个有经验的程序员,你可能有某些习惯来进行程序的优化。有时候我们之前的优化并不适用于.Net平台。
我们的优化可能会起到适得其反的效果,尤其是你试着去做编译的优化。
你的行为可能会妨碍JIT编译器的最优化。
实际上你只要写出精简的代码,其他的工作交给JIT去做就可以了。一个常见的问题就是编写长而复杂的函数来避免函数的多次调用。
其实这回让你的程序变的更慢。
CLR通过JIT编译器来把C# 编译器生成的IL语言编译成特定的机器语言。
这个任务会在你的程序的运行周期内分批运行。当你的程序运行时,CLR会以函数为基本单位来触发JIT编译器。
小的函数会加快你的程序的启动速度,相反如果长程序运行时IL代码全部编译的话,会让程序处于较长的等待状态。
我们完全可以把代码重构为较小的函数来让JIT减少编译无关的代码。如下例子:
1: public string BuildMsg(bool takeFirstPath)
2: {
3: StringBuilder msg = new StringBuilder();
4: if (takeFirstPath)
5: {
6: msg.Append("A problem occurred!");
7: msg.Append("Error!");
8: }
9: else
10: {
11: msg.Append("This is not bad!");
12: msg.Append("Success!!");
13: }
14: return msg.ToString();
15: }
当BuildMsg函数第一次被调用,所有的分支都会被编译。但是实际上只有一个分支会运行。
想象一下如果写如下代码:
1: public string BuildMsg2(bool takeFirstPath)
2: {
3: StringBuilder msg = new StringBuilder();
4: if (takeFirstPath)
5: {
6: return FirstPath();
7: }
8: else
9: {
10: return SecondPath();
11: }
12: }
13:
因为程序分支的语句被重构成函数,所以当程序运行时JIT会减少编译的代码。这个例子是为说明而特别设计的,运行时可能没有什么差别。但是想想我们实际开发中是不是写了大量的这样的代码。想想如果一个程序包含20或者更多的分支,当程序第一次运行时JIT编译器会编译所有的分支。如果一个分支因为未知的错误,你完全可以避免JIT编译的运行时间。
短小简洁的方法还可以使得JIT编译器更容易支持enregistration,enregistration指选择哪些局部变量放入寄存器中存储,而不存储在堆栈中,较少的局部变量将使得JIT编译器更容易做最合适的enregistration选择,同时方法中控制流的简单性也影响着JIT编 译器如何做更好的enregistration。
JIT编译器还会对内联方法做决定,内联意味着将函数调用直接替换为函数体内的代码,例如属性中的get和set访问器,就会被看做是内联方法。