2016-04-29 102 views
0

我前幾天和一位同事討論了這個假設情況。運行編譯代碼時C# - 變量範圍和處理如何影響處理效率?

public void Main() 
{ 
    string1 = null; 
    string2 = null, 
    MyDto dto = Repository.GetDto(); 

    foreach(var row in dto.Rows) 
    { 
     ProcessStrings(row, string1, string2) 
    } 
} 

public void ProcessStrings(DataRow row, string string1, string string2) 
{ 
    string1 = GetStringFromDataRow(row, 1); 
    string2 = GetStringFromDataRow(row, 2); 

    // do something with the strings 
} 

如何將這些在處理不同:考慮這個僞代碼:

public void Main() 
{ 
    MyDto dto = Repository.GetDto(); 

    foreach(var row in dto.Rows) 
    { 
     ProcessStrings(row); 
    } 
} 

public void ProcessStrings(DataRow row) 
{ 
    string string1 = GetStringFromDataRow(row, 1); 
    string string2 = GetStringFromDataRow(row, 2); 

    // do something with the strings 
} 

那麼這個功能相同的選擇嗎?我們是否認爲第二個版本的效率更高一些,因爲字符串變量會佔用較少的內存並且只能被放置一次,而在第一個版本中,它們在循環的每一遍都會被處理掉?

如果第二個版本中的字符串被refout參數傳遞,會有什麼區別嗎?

+1

他們沒有被處置。他們正在GC'd。 – Karolis

+0

我期望第二個版本稍微慢一點*,因爲你傳遞的是不必要的參數。您正在交易參數的局部變量,但兩者都只是對實際字符串對象的引用。 –

+1

@PieterWitvoet在CPU級這兩個例子可以處理使用CPU寄存器和/或疊層,其可能或可能不實際具有相同的執行配置文件的變量和參數。換句話說,即使C#代碼不同,在最終代碼中可能根本就沒有任何區別。然而,有些代碼很可能會被移動,但是我懷疑這是否會在高度理論層面上起作用。 –

回答

2

當您處理「稍微更高效」的優化級別時,您可能無法看到整個圖景並最終導致「邊際效率較低」。

這裏這個答案的風險同樣的事情,但與告誡,讓我們來看看假設:

存儲字符串轉換成變量創建字符串的新實例

一點都不。一個字符串是一個對象,你在變量中存儲的是對該對象的引用。在32位系統上,這個引用的大小是4個字節,在64位上是8個。沒有更多,沒有更多。移動4/8字節是開銷,你不會注意到很多。

所以既不的兩個例子,我們所擁有的有關方法氣質的信息很少被調用,創建等等這算他們相當於比其他更多或更少的字符串。

那麼有什麼不同呢?

那麼在一個例子中,你正在將兩個字符串引用存儲到局部變量中。這很可能是cpu寄存器。可能是堆棧中的內存。很難說,取決於其餘的代碼。有關係嗎?不大可能。

在其他例子中,你正在傳遞兩個參數爲null,然後在本地重新使用這些參數。這些參數可以作爲cpu寄存器或堆棧存儲器傳遞。和其他一樣。它有關係嗎?一點也不。

所以最有可能是完全沒有任何區別。

注意一件事,你提的「處置」。該術語保留用於實現IDisposable的對象,然後通過在這些對象上調用IDisposable.Dispose來處置這些對象。字符串不是這樣的對象,這與這個問題無關。

如果您的意思是「垃圾收集」,那麼既然我已經確定這兩個示例都不會因爲您提出的差異而創建比其他對象多或少的對象,這也是無關緊要的。

這並不重要,但是。這是不重要的,你或我或你的同事認爲將會產生影響。不知道是完全不同的,這使我...

真正的尖端我可以給有關優化:

  1. 措施
  2. 措施
  3. 措施
  4. 理解
  5. 確認您理解正確
  6. 變化,如果可能的話

你測量,使用一個分析器找到真正的瓶頸和實時揮金如土在你的代碼,然後明白,爲什麼那些瓶頸,然後確保您的理解是正確的,那麼你可以看到,如果你可以改變它。

在你的代碼,我會大膽猜測,如果你來分析你的程序,你會發現,這兩個例子絕對沒有對運行時間任何效果。如果他們有效果它將在納秒級。最有可能的是,查看分析器結果的行爲會給你一個或多個關於你的程序的「呃,這很奇怪」的實現,你會發現比這裏的變量更大的瓶頸。

+0

謝謝。我們測量的東西,並意識到這種差異的影響可能會忽略不計。這只是一個好奇心問題,並且希望瞭解編譯代碼如何最終被處理器解釋。 –

+1

在這個詳細程度上,我會編寫代碼給你最溫暖的模糊,並讓編譯器實際的細節。換句話說,例如#1。 –

2

在這兩種替代方法中,GetStringFromDataRow每次都會創建一個新字符串。無論您將參考存儲到本地變量中的參數字符串還是參數變量參數(與您的案例中的本地變量本質上沒有太大差別)都無關緊要。想象你甚至沒有將結果GetStringFromDataRow分配給任何變量 - 字符串實例仍然被創建並存儲在內存中的某個地方,直到垃圾收集。如果你通過引用傳遞你的字符串 - 它不會有太大的區別。您將能夠重新使用內存位置來將參考存儲到創建的字符串(您可以將其視爲字符串實例的內存地址),但不能將字符串內容存儲到位置。