1. ホーム
  2. c#

[解決済み] フィールドとプロパティの比較 パフォーマンスの最適化

2023-06-06 05:15:49

質問

この質問はパフォーマンスのみに関連していることに注意してください。設計指針、哲学、互換性、移植性、および純粋な性能に関連しないものはすべて省略しましょう。ありがとうございました。

さて、質問です。私はいつも、C# のゲッター/セッターは実際には偽装されたメソッドであるため、パブリック フィールドの読み取りはゲッターを呼び出すよりも高速でなければならないと仮定しています。

そこで、私はテスト(以下のコード)を行って確認しました。しかし、このテストは期待された結果しか出しません (すなわち フィールドはゲッターよりも速く、34%です。 ) もし であれば、Visual Studioの内部から実行します。

コマンドラインから実行すると、ほぼ同じタイミングで表示されるのですが...。

唯一の説明は、CLRが追加の最適化を行うことです(私がここで間違っているならば、訂正してください)。

これらのプロパティがより洗練された方法で使用される実際のアプリケーションでは、同じ方法で最適化されるとは思えません。

現実の生活では、プロパティはフィールドよりも遅いという考えを証明または反証するために私を助けてください。

質問は、CLR が動作を変更し、パブリック フィールドがゲッターを上回るようにするには、どのようにテスト クラスを修正すればよいかということです。または、内部ロジックのない任意のプロパティがフィールドと同じように動作することを教えてください (少なくともゲッターで)。

EDIT: 私は Release x64 ビルドについてだけ話しています。

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;
    }
}

どのように解決するのですか?

すでに他の方がおっしゃっているように、ゲッターは インライン .

インライン化を回避したい場合は

  • 自動プロパティを手動プロパティに置き換える。

    class A 
    {
        private double p;
        public double P
        {
            get { return p; }
            set { p = value; }
        }
    } 
    
    
  • で、ゲッターをインライン化しないようにコンパイラに指示します(気が向いたら両方でも)。

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

最初の変更ではパフォーマンスに違いはありませんが、2 番目の変更ではメソッド呼び出しのオーバーヘッドが明確に示されていることに注意してください。

手動プロパティ。

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

ゲッターのインライン化を行わない。

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