简体   繁体   English

为什么结构比类慢?

[英]Why are structs slower than classes?

I'm creating a C# console-app. 我正在创建一个C#console-app。 I have some critical paths and thought that creating structs would be faster than creating classes since I would not need garbage collection for structs. 我有一些关键路径,并认为创建结构比创建类更快,因为我不需要对结构进行垃圾回收。 In my test however I found the opposite. 在我的测试中,我发现了相反的结果。

In the test below, I create 1000 structs and 1000 classes. 在下面的测试中,我创建了1000个结构和1000个类。

class Program
{
    static void Main(string[] args)
    {
        int iterations = 1000;
        Stopwatch sw = new Stopwatch();

        sw.Start();
        List<Struct22> structures = new List<Struct22>();
        for (int i = 0; i < iterations; ++i)
        {
            structures.Add(new Struct22());
        }
        sw.Stop();
        Console.WriteLine($"Struct creation consumed {sw.ElapsedTicks} ticks");

        Stopwatch sw2 = new Stopwatch();
        sw2.Start();
        List<Class33> classes = new List<Class33>();
        for (int i = 0; i < iterations; ++i)
        {
            classes.Add(new Class33());
        }
        sw2.Stop();
        Console.WriteLine($"Class creation consumed {sw2.ElapsedTicks} ticks");


        Console.ReadLine();
    }
}

My classe / struct are simple: 我的classe / struct很简单:

class Class33
{
    public int Property { get; set; }
    public int Field;
    public void Method() { }
}

struct Struct22
{
    public int Property { get; set; }
    public int Field;
    public void Method() { }
}

Results (drum roll please...) 结果(请滚筒......)

Struct creating consuming 3038 ticks
Class creating consuming 404 ticks

So the question is: Why would it take close to 10x the amount of time for a Class than it does for a Struct ? 所以问题是: 为什么一个Class的时间量比结束的时间要接近10倍?

EDIT. 编辑。 I made the Program "Do something" by just assigning integers to the properties. 我通过将属性分配给属性来使程序“做某事”。

 static void Main(string[] args)
    {
        int iterations = 10000000;
        Stopwatch sw = new Stopwatch();

        sw.Start();
        List<Struct22> structures = new List<Struct22>();
        for (int i = 0; i < iterations; ++i)
        {
            Struct22 s = new Struct22()
            {
                Property = 2,
                Field = 3
            };
            structures.Add(s);
        }
        sw.Stop();
        Console.WriteLine($"Struct creating consuming {sw.ElapsedTicks} ticks");

        Stopwatch sw2 = new Stopwatch();
        sw2.Start();
        List<Class33> classes = new List<Class33>();
        for (int i = 0; i < iterations; ++i)
        {
            Class33 c = new Class33()
            {
                Property = 2,
                Field = 3
            };
            classes.Add(c);
        }
        sw2.Stop();
        Console.WriteLine($"Class creating consuming {sw2.ElapsedTicks} ticks");


        Console.ReadLine();
    }

and the result is astounding to me. 结果令我震惊。 Classes are still at least 2x but the simple fact of assigning integers had a 20x impact! 类仍然是至少2倍,但分配整数的简单事实有20倍的影响!

Struct creating consuming 903456 ticks
Class creating consuming 4345929 ticks

EDIT: I removed references to Methods so there are no reference types in my Class or Struct: 编辑:我删除了对方法的引用,因此我的类或结构中没有引用类型:

class Class33
{
    public int Property { get; set; }
    public int Field;
}

struct Struct22
{
    public int Property { get; set; }
    public int Field;
}

The performance difference can probably (or at least in part) be explained by a simple example. 性能差异可能(或至少部分)可以通过一个简单的例子来解释。

For structures.Add(new Struct22()); 对于structures.Add(new Struct22()); this is what really happens: 这才是真正发生的事情:

  • A Struct22 is created and intialized. Struct22已创建并初始化。
  • The Add method is called, but it receives a copy because the item is a value type . 调用Add方法,但它接收副本,因为该项是值类型

So calling Add in this case has overhead, incurred by making a new Struct22 and copying all fields and properties into it from the original. 因此,在这种情况下调用Add产生开销,这是通过创建一个新的Struct22并从原始文件中复制所有字段和属性而产生的。


To demonstrate, not focusing on speed but on the fact that copying takes place: 为了证明,不是关注速度,而是关注复制的事实:

private static void StructDemo()
{
    List<Struct22> list = new List<Struct22>();

    Struct22 s1 = new Struct22() { Property = 2, Field = 3 };  // #1
    list.Add(s1);                            // This creates copy #2
    Struct22 s3 = list[0];                   // This creates copy #3

    // Change properties:
    s1.Property = 777;
    // list[0].Property = 888;    <-- Compile error, NOT possible
    s3.Property = 999;

    Console.WriteLine("s1.Property = " + s1.Property);
    Console.WriteLine("list[0].Property = " + list[0].Property);
    Console.WriteLine("s3.Property = " + s3.Property);
}

This will be the output, proving that both Add() and the use of list[0] caused copies to be made: 这将是输出,证明Add()list[0]导致了副本:

s1.Property = 777 s1.Property = 777
list[0].Property = 2 list [0] .Property = 2
s3.Property = 999 s3.Property = 999

Let this be a reminder that the behaviour of structs can be substantially different compared to objects, and that performance should be just one aspect when deciding what to use. 让我们提醒一下,与对象相比,结构的行为可能会有很大的不同,在决定使用什么时,性能应该只是一个方面。

As commented, deciding on struct vs class has many considerations. 如评论所述,决定struct vs class有很多考虑因素。 I have not seen many people concerned with instantiation as it is usually a very small part of the performance impact based on this descision. 我没有看到很多人关心实例化,因为它通常只是基于这种决策的性能影响的一小部分。

I ran a few tests with your code and found it interesting that as the number of instances increases the struct is faster. 我用你的代码运行了一些测试,并发现有趣的是,随着实例数量的增加,结构更快。

I cant answer your question as it appears that your assertion is not true. 我无法回答你的问题,因为看来你的断言不正确。 Classes do not always instantiate faster than Structs. 类并不总是比Structs更快地实例化。 Everything I have read states the opposite, but your test produces the interesting results you mentioned. 我读过的所有内容都反过来说,但是你的测试会产生你提到的有趣结果。

There are tools you can use to really dig in and try to find out why you get the results you do. 您可以使用一些工具来深入挖掘并尝试找出您获得结果的原因。

10000 
Struct creation consumed 2333 ticks
Class creation consumed 1616 ticks

100000
Struct creation consumed 5672 ticks
Class creation consumed 8459 ticks

1000000
Struct creation consumed 73462 ticks
Class creation consumed 221704 ticks

List<T> stores T objects in internal Array. List<T>将T对象存储在内部Array中。

Each time when the limit of capacity is reached, new double sized internal array is created and all values from old array are copied ... 每次达到容量限制时,都会创建新的双倍大小的内部数组,并复制旧数组中的所有值...

When you create an empty List and try to populate it 1000 times, internal array recreated and copied about 10 times. 当您创建一个空List并尝试将其填充1000次时,内部数组将重新创建并复制约10次。

So in Your example classes could create slower, but each time when new array is created, List should copy only references to objects in case of List of Class, and all structure data in case of List of Struct ... 所以在你的示例中,类可能创建得更慢,但每次创建新数组时,List应该只复制对类的List的对象的引用,以及结构列表的所有结构数据...

Try to create List with initial capacity initialized, for your code it should be: 尝试创建初始容量初始化的List,对于您的代码应该是:

new List<Struct22>(1000)

in this case internal array wont be recreated and structure case will work much faster 在这种情况下,内部数组不会被重新创建,结构案例将更快地工作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM