现场VS属性。性能优化属性、性能、现场、VS

2023-09-03 00:01:42 作者:自命不凡

请注意,这个问题涉及到唯一的表现。让我们跳过的设计准则,经营理念,兼容性,可移植性和任何东西是没有关系的纯粹的性能。谢谢你。

现在的问题。我一直认为,因为C#getter / setter方法​​是真正的伪装方法,然后读公共领域必须比调用一个getter快。

因此​​,为了确保我做了一个测试(code以下)。不过本次测试仅产生预期的结果(即字段快于干将在34%)如果从Visual Studio中运行它。

深入剖析 iOS 性能优化

在你的命令行运行它显示pretty的大致相同的时间...

唯一的解释可能是,CLR做更多优化(纠正我,如果我错了这里)。

我不认为在在更复杂的方式被使用这些属性实际应用它们会以同样的方式进行优化。

请帮我证明或反驳的想法,在现实生活中性能优于领域慢一些。

现在的问题是 - 我应该怎么修改测试类,使CLR改变行为,使公共领域outperfroms的干将。或者告诉我,如果没有内部逻辑任何财产将执行同一个领域(至少在吸气)

编辑:我只谈论发布的x64版本的

 使用系统;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;
使用System.Diagnostics程序;
使用了System.Runtime.InteropServices;

命名空间PropertyVsField
{
    类节目
    {
        静态INT LEN = 20000000;
        静态无效的主要(字串[] args)
        {
            名单< A> A =新的名单,其中,A>(LEN);
            名单< B> B =新的名单,其中,B>(LEN);

            随机R =新的随机(DateTime.Now.Millisecond);

            的for(int i = 0; I< LEN;我++)
            {
                双P = r.NextDouble();
                a.Add(新A(){P =});
                b.Add(新的B(){P =});
            }

            秒表SW =新的秒表();

            双D = 0.0;

            sw.Restart();
            的for(int i = 0; I< LEN;我++)
            {
                D + = A [1] .P;
            }

            sw.Stop();

            Console.WriteLine(自动吸气{0} {1}。,sw.ElapsedTicks,D);

            sw.Restart();
            的for(int i = 0; I< LEN;我++)
            {
                D + = B [I] .P;
            }

            sw.Stop();

            Console.WriteLine(字段{0} {1}。,sw.ElapsedTicks,D);

            到Console.ReadLine();
        }
    }

    A级
    {
        公共双p {获得;组; }
    }
    B类
    {
        公共双磷;
    }
}
 

解决方案

正如其他人已经提到,吸气剂的内联的。

如果你想避免内联,你必须

与手工换上了自动属性:

  A级
{
    私人双磷;
    大众双P
    {
        {返回磷; }
        集合{P =价值; }
    }
}
 

和告诉编译器不内联的吸气剂(或两者兼而有之,如果你喜欢的话):

  [MethodImpl(MethodImplOptions.NoInlining)
        {返回磷; }
 

请注意,第一个变化不会对性能有差别,而第二个变化呈现出明显的方法调用的开销:

手册属性:

 自动吸气。 519005. 10000971,0237547。
      领域。 514235. 20001942,0475098。
 

吸气剂的无内联

 自动吸气。 785997. 10000476,0385552。
      领域。 531552. 20000952,077111。
 

Please note this question related to performance only. Lets skip design guidelines, philosophy, compatibility, portability and anything what is not related to pure performance. Thank you.

Now to the question. I always assumed that because C# getters/setters are really methods in disguise then reading public field must be faster than calling a getter.

So to make sure I did a test (the code below). However this test only produces expected results (ie fields are faster than getters at 34%) if you run it from inside Visual Studio.

Once you run it from command line it shows pretty much the same timing...

The only explanation could be is that the CLR does additional optimisation (correct me if I am wrong here).

I do not believe that in real application where those properties being used in much more sophisticated way they will be optimised in the same way.

Please help me to prove or disprove the idea that in real life properties are slower than fields.

The question is - how should I modify the test classes to make the CLR change behaviour so the public field outperfroms the getters. OR show me that any property without internal logic will perform the same as a field (at least on the getter)

EDIT: I am only talking about Release x64 build.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace PropertyVsField
{
    class Program
    {
        static int LEN = 20000000;
        static void Main(string[] args)
        {
            List<A> a = new List<A>(LEN);
            List<B> b = new List<B>(LEN);

            Random r = new Random(DateTime.Now.Millisecond);

            for (int i = 0; i < LEN; i++)
            {
                double p = r.NextDouble();
                a.Add(new A() { P = p });
                b.Add(new B() { P = p });
            }

            Stopwatch sw = new Stopwatch();

            double d = 0.0;

            sw.Restart();
            for (int i = 0; i < LEN; i++)
            {
                d += a[i].P;
            }

            sw.Stop();

            Console.WriteLine("auto getter. {0}. {1}.", sw.ElapsedTicks, d);

            sw.Restart();
            for (int i = 0; i < LEN; i++)
            {
                d += b[i].P;
            }

            sw.Stop();

            Console.WriteLine("      field. {0}. {1}.", sw.ElapsedTicks, d);

            Console.ReadLine();
        }
    }

    class A
    {
        public double P { get; set; }
    }
    class B
    {
        public double P;
    }
}

解决方案

As others have already mentioned, the getters are inlined.

If you want to avoid inlining, you have to

replace the automatic properties with manual ones:

class A 
{
    private double p;
    public double P
    {
        get { return p; }
        set { p = value; }
    }
} 

and tell the compiler not to inline the getter (or both, if you feel like it):

        [MethodImpl(MethodImplOptions.NoInlining)]
        get { return p; }

Note that the first change does not make a difference in performance, whereas the second change shows a clear method call overhead:

Manual properties:

auto getter. 519005. 10000971,0237547.
      field. 514235. 20001942,0475098.

No inlining of the getter:

auto getter. 785997. 10000476,0385552.
      field. 531552. 20000952,077111.