C#中for和foreach迴圈的效能

來源:互聯網
上載者:User

大家先來看看如下三個迴圈:

            int[] foo = new int[100];

          1,  foreach (int i in foo)
                Console.WriteLine(i.ToString());

          2,for(int index=0;index<foo.Length;index++)
                Console.WriteLine(foo[index].ToString());

          3,int len=foo.Length;
            for(int index=0;index<len;index++)
                Console.WriteLine(foo[index].ToString());
 這三個迴圈是我在看《Effective C#》中看到的,發現書中說第三個迴圈和如下代碼等效,經過使用ILDasm.exe工具查看IL代碼發現這個說法並不正確:

int len=foo.Length;

for(int index=0;index<len;index++)

{

      if(index<foo.Length)

           Console.WriteLine(foo[index].ToString());

      else

            throw new IndexOutOfRangeException();

}

書中的看法是數組的邊界測試會被執行兩次(編譯器產生的程式碼一次,JIT編譯階段還要執行一次檢查),但是的確沒有在IL代碼中發現C#的編譯器產生類似的邏輯,所以這個說法有問題!

一般C++轉過來的程式員都很喜歡這樣寫迴圈,認為這樣就不會每一次迴圈都計算一次Length屬性的值了,可以帶來效能上的提升!經查看IL代碼,實際情況也就是如此!

但是,這樣寫會帶來另外的問題,那就是破壞了JIT對代碼的進行的最佳化,這樣的寫法在每一次迴圈中都要做數組的邊界檢查,這樣也帶來了效能上的損失,而且這個損失要比每次計算Length要大,如果我們按第二種寫法,JIT只在第一次迴圈之前檢查一次數組界限(JIT這種最佳化只針對f迴圈中訪問一維0基數組,並且索引是0和Length之間的元素)

看來JIT不喜歡我們這樣協助他最佳化代碼,這樣反而破壞了JIT本身的最佳化!

我們再來看看第一種寫法和第二種寫法,通過查看IL代碼,他們產生的程式碼比較類似,差別是使用foreach迴圈是把數組元素放到i變數裡!

C#編譯器對第一種寫法(使用foreach迴圈)針對數組做了特殊的處理,並沒有像其他集合那樣在內部使用迭代器,這裡如果使用迭代器的話會導致裝箱和拆箱操作,這樣會帶來效能上的損失!看來C#編譯器總是可以為foreach產生很高效率的代碼,而且可以帶來很多其他的好處,例如簡化代碼的編寫,或是將來把foo變成其他集合 而foreach迴圈不必修改(使用for迴圈必須修改代碼),運算元強制類型轉換等

請大家多多指教啊!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.