2016-02-26 86 views
3

我知道可變結構是邪惡的。但是,我仍然想比較一個結構數組的性能與一組對象的性能。這是我到目前爲止的struct array vs object array c#

public struct HelloStruct 
    { 
     public int[] hello1; 
     public int[] hello2; 
     public int hello3; 
     public int hello4; 
     public byte[] hello5; 
     public byte[] hello6; 
     public string hello7; 
     public string hello8; 
     public string hello9; 
     public SomeOtherStruct[] hello10; 

    } 

    public struct SomeOtherStruct 
    { 
     public int yoyo; 
     public int yiggityyo; 
    } 

    public class HelloClass 
    { 
     public int[] hello1; 
     public int[] hello2; 
     public int hello3; 
     public int hello4; 
     public byte[] hello5; 
     public byte[] hello6; 
     public string hello7; 
     public string hello8; 
     public string hello9; 
     public SomeOtherClass[] hello10; 

    } 
     public class SomeOtherClass 
    { 
     public int yoyo; 
     public int yiggityyo; 
    } 

static void compareTimesClassVsStruct() 
    { 
     HelloStruct[] a = new HelloStruct[50]; 
     for (int i = 0; i < a.Length; i++) 
     { 
      a[i] = default(HelloStruct); 
     } 

     HelloClass[] b = new HelloClass[50]; 
     for (int i = 0; i < b.Length; i++) 
     { 
      b[i] = new HelloClass(); 
     } 
     Console.WriteLine("Starting now"); 
     var s1 = Stopwatch.StartNew(); 
     for (int i = 0; i < _max; i++) 
     { 
      a[i % 50].hello1 = new int[] { 1, 2, 3, 4, i % 50 }; 
      a[i % 50].hello3 = i; 
      a[i % 50].hello7 = (i % 100).ToString(); 
     } 
     s1.Stop(); 

     var s2 = Stopwatch.StartNew(); 
     for (int j = 0; j < _max; j++) 
     { 
      b[j % 50].hello1 = new int[] { 1, 2, 3, 4, j % 50 }; 
      b[j % 50].hello3 = j; 
      b[j % 50].hello7 = (j % 100).ToString(); 
     } 
     s2.Stop(); 

     Console.WriteLine(((double)(s1.Elapsed.TotalSeconds))); 
     Console.WriteLine(((double)(s2.Elapsed.TotalSeconds))); 
     Console.Read(); 

    } 

這裏有一些事情我想了解。

首先,由於數組存儲結構,當我嘗試使用索引操作數組訪問一個結構,我應該得到的結構或使原有結構的引用的副本?在這種情況下,當我運行代碼後檢查數組時,我得到了變異的結構值。這是爲什麼?

其次,當我比較內CompareTimesClassVsStruct()時序我得到大致相同的時間。這背後的原因是什麼?有沒有什麼情況下使用一個結構數組或對象數組會超越另一個呢?

感謝

+0

MSDN有關[在類和結構之間選擇]的指導(https://msdn.microsoft.com/zh-cn/library/ms229017.aspx)。 MSDN在底部提供了方便的子彈點以加快閱讀速度。也就是說,解決結構vs類最簡單的方法是使用MSDN的指導原則,「框架中的大多數類型應該是類。」 – Brian

回答

5

當您訪問結構數組的元素的屬性,你是不是在結構的拷貝操作 - 您操作的結構本身。 (這不是一個List<SomeStruct>在那裏你會在複印件上進行操作也是如此,並在您的示例代碼甚至不會編譯。)

你也看到類似的時間,是因爲時代正在由(j % 100).ToString()扭曲和環路內的new int[] { 1, 2, 3, 4, j % 50 };。這兩條語句花費的時間量使得數組元素訪問所花費的時間變得相當短。

我改變了一下測試應用程序,我得到了9.3s的結構數組和10s的類數組(因爲1,000,000,000個循環)的訪問次數,所以struct數組明顯更快,但非常微不足道。

的一件事,它可以使結構數組更快地迭代是局部性。在迭代結構數組時,相鄰元素在內存中相鄰,這可減少處理器高速緩存未命中的數量。

級陣列中的元件不相鄰(雖然在陣列中的元素的參考,當然),這可能會導致更多的處理器高速緩存未命中,而你迭代這個數組。

另一件需要注意的事情是結構數組中連續字節的數量實際上是(number of elements) * (sizeof(element)),而類數組中的連續字節數是(number of elements) * (sizeof(reference)),其中引用的大小是32位或64位,取決於內存模型。

這可以是與大結構,其中陣列的總尺寸將超過2^31字節的大陣列的問題。

你可能在速度上看到的另一個區別是,當傳遞大型結構作爲參數時 - 顯然將值傳遞給堆棧上引用類型的引用副本比傳遞值副本更快大結構。

最後請注意,你的樣本結構是不是很有代表性。它包含很多引用類型,所有這些類型都將存儲在堆的某個地方,而不是數組本身。作爲一個經驗法則,結構的大小不應該超過32個字節(確切的限制是爭議),它們應該只包含原始類型(blittable),它們應該是不可變的。而且,通常情況下,無論如何,你都不應該擔心做出結構性的事情,除非你有可證明的性能需求。

+0

謝謝。我想從你那裏得到一個解釋:當你說示例結構不是很具代表性,因爲它包含引用類型,你的意思是數組將保持引用的位置,但所有的引用類型(例如字符串在我的例子)在結構將被存儲在堆,結構持有指針這些引用類型?如果是這種情況,那麼公式'(no of elements)*(sizeof(element))'將成爲'(no of value-type elements)*(sizeof(value-type elements))+(參考類型no元素)*(sizeof(reference))'。那是對的嗎? – user2635088

+1

@ user2635088是的,這是絕對正確的。 –

6

首先,由於數組存儲結構,當我嘗試使用索引操作數組訪問一個結構,我應該得到的結構或使原有結構的引用的副本?

讓我告訴你實際發生的情況,而不是回答你的混亂的問題或問題。

  • 數組是變量的集合
  • 應用於數組時的索引操作會產生變量
  • 成功突變可變結構的字段要求您手頭有變量,其中包含您希望進行變異的結構。

所以,現在你的問題:你應該得到一個參考結構?

  • 是的,在某種意義上,變量指的是存儲
  • 不,從變量中不包含對對象的引用;結構不是裝箱的。
  • 不,從某種意義上講,變量不是ref變量。但是,如果您已經對索引器的結果調用了一個實例方法,那麼將爲您生成一個ref變量;那個ref變量被稱爲「this」,並且它會被傳遞給你的實例方法。

您會看到這會有多混淆。最好不要考慮參考。考慮變量。索引數組會產生變量

現在推導出如果您使用了列表而不是數組,那麼會發生什麼情況,因爲知道列表的getter索引器會生成一個值而不是一個變量。

在這種情況下,當我運行代碼後檢查數組時,我得到了變異的結構值。這是爲什麼?

您突變了一個變量。

我大致是同一時間。這背後的原因是什麼?

區別是如此之小以至於它被兩種情況下所做的所有內存分配和內存拷貝所淹沒。這是真正的外賣。數組中存儲的可變值類型的操作稍微快一點嗎?有可能。 (它們還可以節省採集壓力,這通常是更相關的性能指標。)但是,儘管相對節省量可能很大,但節省量佔總體工作量的百分比通常很小。如果你有性能問題,那麼你想攻擊最昂貴的東西,而不是已經很便宜的東西。

+0

感謝埃裏克 - 變量和值!我會記住這一點! – user2635088

+0

我想爲Eric的答案添加一個更多的細節。如果你已經將數組索引賦值給一個變量(例如'var myStruct = a [index];'),並將其更新爲'myStruct.hello3 = 1234;',它將不會在struct數組中更新'a [index]',因爲它是從'a [index]'中檢索到的結構的副本上運行的。但'a [index] .hello3 = 1234;'按預期工作。 – stun