C#中容易被忽視的foreach
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
有句俗語(yǔ):百姓日用而不知。我們c#程序員很喜歡,也非常習(xí)慣地用foreach。今天呢,我就帶大家一起探索foreach,走,開(kāi)始我們的旅程。 一、for語(yǔ)句用地好好的,為什么要提供一個(gè)foreach?
首先,for循環(huán),需要知道循環(huán)的次數(shù),foreach不需要。其次,for循環(huán)在遍歷對(duì)象的時(shí)候,略顯麻煩,還需要通過(guò)下標(biāo)索引找到當(dāng)前對(duì)象,foreach不需要這么麻煩,顯得更優(yōu)雅。最后,for循環(huán)需要知道集合的細(xì)節(jié),foreach不需要知道。 這一切的好處,得益于微軟的封裝,那我們看看foreach生成的IL代碼:
怎樣的對(duì)象才能使用foreach呢?從微軟的文檔上看,實(shí)現(xiàn)了IEnumerable接口的對(duì)象,可以使用foreach,此接口只定義了一個(gè)方法:public System.Collections.IEnumerator GetEnumerator (); 有意思的是,它返回了一個(gè)IEnumerator接口,再看看這個(gè)接口: 有一個(gè)屬性:Current兩個(gè)方法MoveNext()、Reset(),現(xiàn)在我們回過(guò)頭來(lái)看看生成的IL代碼,真相大白。foreach只不過(guò)是個(gè)好吃的語(yǔ)法糖而已,編譯器幫我們做好了一切。和直接寫(xiě)foreach類似的用法還有一個(gè),就是對(duì)象的Foreach方法: list.ForEach(n => { //to do sth }); 那問(wèn)題就來(lái)了,都是foreach,我該用哪個(gè)? 忍不住看看微軟的源碼: internal void ForEach(Action<T> action) { foreach (T x in this) { action(x); } } 其實(shí),就是定義了一個(gè)委托,我們把想要做的事情定義好,它來(lái)執(zhí)行。這和直接使用foreach有何區(qū)別?我又忍不住好奇心,寫(xiě)了一段代碼,比較了for和foreach的性能,先上結(jié)果: 說(shuō)明下,最后一個(gè)是對(duì)象調(diào)用Foreach方法。數(shù)據(jù)反映的是隨著數(shù)據(jù)規(guī)模下降,看運(yùn)行時(shí)間有什么變化。從1億次循環(huán)到1萬(wàn)次循環(huán),耗時(shí)從幾百毫秒到1毫秒以內(nèi)。從圖上,明顯能看出性能差異,是從千萬(wàn)級(jí)別開(kāi)始,for的性能最好,其次是對(duì)象的Foreach方法,最后是foreach。 for和foreach的性能差異,我們尚且能理解,但是對(duì)象的Foreach和直接foreach差異從何而來(lái)?我冥思苦想,百思不得其解。我試圖從內(nèi)存分配和垃圾回收的機(jī)制方向去理解,但是沒(méi)有突破。我想著,直接foreach耗時(shí),是不是因?yàn)椋鄨?zhí)行了什么東西,比如說(shuō)多分配了一些變量,比如說(shuō),內(nèi)存中這么大數(shù)據(jù)量,垃圾回收機(jī)制,不可能無(wú)動(dòng)于衷,是不是垃圾回收機(jī)制導(dǎo)致的程序變慢,進(jìn)而影響了性能。 我在循環(huán)完后,強(qiáng)行執(zhí)行了一次GC,才釋放了13.671875k,說(shuō)明循環(huán)中,執(zhí)行GC也沒(méi)有什么意義,回收不了垃圾,但是如果循環(huán)中,頻繁執(zhí)行GC,確實(shí)會(huì)導(dǎo)致程序沒(méi)法好好地運(yùn)行。垃圾回收機(jī)制,會(huì)把不再引用的對(duì)象釋放,而整個(gè)循環(huán)過(guò)程中,對(duì)象都在List中,所以GC應(yīng)該不會(huì)運(yùn)行。 那親愛(ài)的程序員朋友,你覺(jué)得對(duì)象的Foreach方法和直接Foreach的性能差異,是怎么產(chǎn)生的呢,歡迎討論,我把源碼貼出來(lái)。
放到Main方法里:
該文章在 2023/5/18 15:19:27 編輯過(guò) |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |