Champ vs propriété. Optimisation des performances

Veuillez noter que cette question concerne uniquement la performance. Permet de sauter les directives de conception, la philosophie, la compatibilité, la portabilité et tout ce qui n'est pas lié à la performance pure. Merci.

Passons maintenant à la question. J'ai toujours supposé que parce que C # getters / setters sont vraiment des méthodes déguisées, la lecture du champ public doit être plus rapide que l'appel d'un getter.

Donc pour m'assurer que j'ai fait un test (le code ci-dessous). Cependant, ce test ne produit que les résultats attendus (c'est-à-dire champs sont plus rapides que les getters à 34%) Si vous l'exécutez depuis Visual Studio.

Une fois que vous l'exécutez à partir de la ligne de commande, il affiche à peu près le même timing...

La seule explication pourrait être que le CLR effectue une optimisation supplémentaire (corrigez-moi si je me trompe ici).

Je ne crois pas que dans une application réelle où ces propriétés sont utilisées de manière beaucoup plus sophistiquée, elles seront optimisées de la même manière.

Aidez-moi à prouver ou à réfuter l'idée que dans la vie réelle les propriétés sont plus lentes que les champs.

La question Est - Comment dois-je modifier les classes de test pour que le CLR change de comportement afin que le champ public surpasse les getters. Ou montrez - moi que toute propriété sans logique interne effectuera la même chose qu'un champ (au moins sur le getter)

EDIT: Je ne parle que de la version 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;
    }
}
58
demandé sur Boppity Bop 2012-03-23 20:30:01

5 réponses

Comme d'autres l'ont déjà mentionné, les accesseurs sont inline.

Si vous voulez éviter l'inlining, vous devez

  • Remplacez les propriétés automatiques par des propriétés manuelles:

    class A 
    {
        private double p;
        public double P
        {
            get { return p; }
            set { p = value; }
        }
    } 
    
  • Et dites au compilateur de ne pas intégrer le getter (ou les deux, si vous en avez envie):

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

Notez que la première modification ne fait pas de différence dans les performances, tandis que la seconde modification montre un surcoût d'appel de méthode clair:

Manuel propriétés:

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

Non inline de la lecture:

auto getter. 785997. 10000476,0385552.
      field. 531552. 20000952,077111.
48
répondu Heinzi 2012-03-23 16:47:04

Jetez un oeil aux Propriétés vs champs-Pourquoi est-ce important? (Jonathan Aneja) article de blog d'un des membres de L'équipe VB sur MSDN. Il décrit l'argument property versus fields et explique également les propriétés triviales comme suit:

Un argument que j'ai entendu pour utiliser des Champs sur des propriétés est que "les champs sont plus rapides" , mais pour les propriétés triviales, ce n'est pas le cas certes, comme le compilateur JIT (Just-In-Time) du CLR intégrera le accès à la propriété et générer code aussi efficace que l'accès à un domaine directement en.

21
répondu JamieSee 2012-03-23 16:54:13

Le JIT inline toute méthode (pas seulement un getter) que ses métriques internes déterminent sera plus rapide en ligne. Étant donné qu'une propriété standard est return _Property;, elle sera inline dans tous les cas.

La raison pour laquelle vous voyez un comportement différent est qu'en mode débogage avec un débogueur attaché, le JIT est considérablement handicapé, pour s'assurer que les emplacements de pile correspondent à ce que vous attendez du code.

Vous oubliez également la règle numéro un de la performance, testant les battements pensée. Par exemple, même si le tri rapide est asymptotiquement plus rapide que le tri par insertion, le tri par insertion est en fait plus rapide pour les entrées extrêmement petites.

11
répondu Guvante 2012-03-23 16:35:46

La seule explication pourrait être que le CLR fait une optimisation supplémentaire (correrct moi si je me trompe ici).

Oui, il s'appelle inlining. Cela se fait dans le compilateur (niveau de code machine-c'est-à-dire JIT). Comme le getter / setter est trivial (c'est-à-dire un code très simple), les appels de méthode sont détruits et le getter/setter écrit dans le code environnant.

Cela ne se produit pas en mode débogage afin de prendre en charge le débogage (c'est-à-dire la possibilité de définir un point d'arrêt dans un getter ou setter).

Dans visual studio, il n'y a aucun moyen de le faire dans le débogueur. Compilez la version, exécutez sans débogueur attaché et vous obtiendrez l'optimisation complète.

Je ne crois pas que dans une application réelle où ces propriétés sont utilisées de manière beaucoup plus sophistiquée, elles seront optimisées de la même manière.

Le monde est plein d'illusions qui sont mauvais. Ils seront optimisés car ils sont toujours triviaux (c'est-à-dire du code simple, donc ils sont en ligne).

6
répondu TomTom 2012-04-27 15:28:16

Il convient de noter qu'il est possible de voir la performance "réelle" dans Visual Studio.

  1. compiler en mode Release avec Optimisations activées.
  2. Allez dans débogage - > Options et paramètres, et décochez " Supprimer l'optimisation JIT sur la charge du module (géré uniquement)".
  3. en option, décochez "Activer juste mon Code" sinon vous ne pourrez peut-être pas entrer dans le code.

Maintenant, l'assembly jitted sera le même même avec le débogueur attaché, vous permettant de faire un pas dans le démontage optimisé si vous le souhaitez. Ceci est essentiel pour comprendre comment le CLR optimise le code.

2
répondu Asik 2013-08-08 20:10:54