Performances d'arborescence d'expression compilées

.net c# expression-trees lambda performance

Question

Si exécuter le code suivant

using System;
using System.Linq.Expressions;
using System.Diagnostics;

public class E
{
    public double V { get; set; }
}

public class Program
{
    public static void Main()
    {
        E e = new E();
        Func<double> f = () => e.V;

        Expression expr = Expression.Property(Expression.Constant(e), "V");
        Expression<Func<double>> exp = Expression.Lambda<Func<double>>(expr);
        Func<double> ef = exp.Compile();

        e.V = 123;

        int attempts = 5;
        for (int j = 0; j < attempts; j++)
        {
            int c = 100000;

            double[] r1 = new double[c];
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < c; i++)
            {
                r1[i] = f();
            }
            sw.Stop();

            double[] r2 = new double[c];
            Stopwatch sw2 = new Stopwatch();
            sw2.Start();
            for (int i = 0; i < c; i++)
            {
                r2[i] = ef();
            }
            sw2.Stop();

            double rat = (double)sw.ElapsedTicks / sw2.ElapsedTicks;

            Console.WriteLine(rat);
        }
    }
}

alors il s'avère que l'expression compilée est beaucoup plus lente qu'un lambda. Est-ce résultat attendu? Est-il possible de réécrire l'expression en quelque sorte pour obtenir un code équivalent mais qui fonctionnera plus rapidement?

Réponse populaire

votre délégué f est créé avec une classe générée compilée avec un champ e de type E et une valeur d'accès comme celle-ci:

return <Target>.e.V;

Dans le second cas (expression), le délégué est créé à l'aide d'une instruction constante qui utilise une clôture comme cible avec un tableau d'objet où e est le premier élément. Le code peut être représenté comme ceci:

return ((E)<Target>.Constants[0]).V;

C'est pourquoi les performances sont meilleures pour le premier cas.

Remarque: avec "Watch window" dans Visual Studio, lorsque vous déboguez le code, vous pouvez inspecter "f.Target" et "ef.Target" pour le confirmer.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi