struct array vs object array c#

use*_*088 4 c# arrays struct

我知道可变结构是邪恶的.但是,我仍然想比较一个结构数组与一个对象数组的性能.这就是我到目前为止所拥有的

 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();

    }
Run Code Online (Sandbox Code Playgroud)

这里发生了一些我想要了解的事情.

首先,由于数组存储结构,当我尝试使用索引操作从数组访问结构时,我应该获得结构的副本还是对原始结构的引用?在这种情况下,当我在运行代码后检查数组时,我得到了变异的struct值.为什么会这样?

其次,当我比较内部的时间时,CompareTimesClassVsStruct()我得到大致相同的时间.这背后的原因是什么?是否有任何情况下使用结构数组或对象数组会胜过另一个?

谢谢

Mat*_*son 6

当您访问结构数组元素的属性时,您不是在结构的副本上操作 - 您正在对结构本身进行操作.(List<SomeStruct>对于您将在副本上运行的位置,情况并非如此,并且示例中的代码甚至无法编译.)

你看到相似时间的原因是因为时间被循环中的扭曲(j % 100).ToString()和扭曲new int[] { 1, 2, 3, 4, j % 50 };.这两个语句所花费的时间使数组元素访问所花费的时间相形见绌.

我稍微更改了测试应用程序,并且我有时间访问9.3s的struct数组和10s的类数组(对于1,000,000,000个循环),因此struct数组明显更快,但非常微不足道.

可以使结构数组更快迭代的一件事是引用的局部性.迭代结构数组时,相邻元素在内存中相邻,这减少了处理器缓存未命中数.

类数组的元素不相邻(当然,虽然引用了数组中的元素),但是当您遍历数组时,这会导致更多的处理器缓存未命中.

另一件需要注意的是结构数组(number of elements) * (sizeof(element))中连续字节的数量是有效的,而类数组中连续字节的数量是(number of elements) * (sizeof(reference))引用大小为32位或64位的位置,具体取决于内存模型.

这可能是大型结构数组的问题,其中数组的总大小将超过2 ^ 31个字节.

您可能在速度上看到的另一个区别是将大型结构作为参数传递 - 显然,将值的引用副本传递给堆栈上的引用类型比通过值传递大型结构的副本要快得多.

最后,请注意您的示例结构不是很有代表性.它包含许多引用类型,所有引用类型都将存储在堆上的某个位置,而不是存储在数组本身中.

根据经验,结构的大小不应超过32个字节(确切的限制是争论的问题),它们应该只包含原始(blittable)类型,它们应该是不可变的.而且,通常情况下,你不应该担心事情的结构,除非你有一个可证明的性能需求.


Eri*_*ert 6

首先,由于数组存储结构,当我尝试使用索引操作从数组访问结构时,我应该获得结构的副本还是对原始结构的引用?

让我告诉你实际发生了什么,而不是回答你那令人困惑的措辞或问题.

  • 数组是变量的集合.
  • 应用于数组时的索引操作会生成变量.
  • 成功地改变可变结构的字段需要您拥有包含要变异的结构的变量.

那么现在问你的问题:你应该获得对结构的引用吗?

  • 是的,从某种意义上说,变量是指存储.
  • 不,从某种意义上说,变量不包含对象的引用 ; 结构不是盒装的.
  • 不,从某种意义上说,变量不是ref变量.
  • 但是,如果你在索引器的结果上调用了一个实例方法,那么就会为你生成一个ref变量; ref变量称为"this",它将被传递给您的实例方法.

你看到这有多混乱.最好不要考虑参考文献.考虑变量.索引数组会生成一个变量.

现在推断出使用列表而不是数组会发生什么,知道列表的getter索引器产生的是值,而不是变量.

在这种情况下,当我在运行代码后检查数组时,我得到了变异的struct值.为什么会这样?

你改变了一个变量.

我大约在同一时间.这背后的原因是什么?

差异非常小,以至于在两种情况下都会被所有内存分配和内存副本所淹没.这是真正的外卖.对存储在数组中的可变值类型的操作是否稍快一些?有可能.(它们也节省了收集压力,这通常是更相关的性能指标.)但是,虽然相对节省可能很大,但节省占总工作的百分比通常很小.如果你遇到性能问题,那么你想攻击最昂贵的东西,而不是那些已经很便宜的东西.