31 votes

Le compilateur C # n'optimise pas les conversions inutiles

Quelques jours en arrière, lors de l'écriture d'une réponse à cette question ici sur le dépassement je me suis un peu surpris par le compilateur C#, qui n'était pas de faire ce que j'ai prévu de faire. Regardez les suivantes pour les extraits de code:

D'abord:

object[] array = new object[1];

for (int i = 0; i < 100000; i++)
{
    ICollection<object> col = (ICollection<object>)array;
    col.Contains(null);
}

Deuxième:

object[] array = new object[1];

for (int i = 0; i < 100000; i++)
{
    ICollection<object> col = array;
    col.Contains(null);
}

La seule différence de code entre les deux extraits est le casting de ICollection<object>. Parce que l'objet[] implémente l'ICollection<objet> interface explicitement, je m'attendais à les deux fragments de code à compiler vers le bas pour la même chose IL et donc être identiques. Cependant, lors de l'exécution de tests de performance sur eux, j'ai remarqué que celle-ci soit environ 6 fois plus rapide que l'ancien.

Après avoir comparé le IL de les deux extraits, j'ai remarqué que les deux méthodes sont identiques, sauf pour un castclass instruction IL dans le premier extrait.

Surpris par ce que je me demande maintenant pourquoi le compilateur C# n'est pas "intelligent" de la ici. Les choses ne sont jamais aussi simple qu'il y paraît, alors pourquoi est le compilateur C# un peu naïf ici?

33voto

Eric Lippert Points 300275

Je suppose que vous avez découvert un bug mineur dans l'optimiseur. Il y a toutes sortes de codes spéciaux pour les tableaux. Merci de l'avoir porté à mon attention.

4voto

Marcel Jackwerth Points 20632

C'est grosso modo, mais je pense que c'est à propos de la Matrice de la relation à son générique IEnumerable.

Dans l' .NET Framework version 2.0, le Tableau de la classe implémente l' Système.Les Collections.Génériques.IList, Système.Les Collections.Génériques.ICollection, et Système.Les Collections.Génériques.IEnumerable les interfaces génériques. L' les implémentations sont fournis aux tableaux au moment de l'exécution, et, par conséquent, ne sont pas visible à la documentation de construire outils. En conséquence, le générique les interfaces n'apparaissent pas dans le syntaxe de déclaration pour le Tableau de la classe, et il n'y a pas de référence thèmes pour l'interface des membres qui sont accessible uniquement par coulée d'un tableau à le générique type d'interface (explicite des implémentations d'interface). La clé chose d'être conscient de quand vous lancez un tableau à l'une de ces interfaces est que les membres qui ajouter, insérer ou supprimer des éléments jeter NotSupportedException.

Consultez l'Article MSDN.

Il n'est pas clair si cette porte .NET 2.0+, mais dans ce cas, il serait parfaitement logique pourquoi le compilateur ne peut pas optimiser votre expression, si elle ne devient valide qu'au moment de l'exécution.

2voto

Hans Passant Points 475940

Ça ne ressemble pas à plus que juste une occasion manquée dans le compilateur pour supprimer la fonte. Il ne fonctionnera que si vous l'écrire comme ceci:

    ICollection<object> col = array as ICollection<object>;

ce qui suggère qu'il est trop prudente, car les moulages peuvent lever des exceptions. Toutefois, il ne fonctionne pas lorsque vous lancez pour la non-générique ICollection. Je voudrais conclure qu'ils ont simplement oublié.

Il y a une plus grande optimisation de la question à l'œuvre ici, le compilateur JIT ne s'applique pas l'invariant de boucle de hissage d'optimisation. Il devrait avoir ré-écrit le code comme ceci:

object[] array = new object[1];
ICollection<object> col = (ICollection<object>)array;
for (int i = 0; i < 100000; i++)
{
    col.Contains(null);
}

Qui est un standard d'optimisation dans le C/C++ générateur de code par exemple. Encore, l'équipe de l'optimiseur ne peut brûler beaucoup de cycles sur le type d'analyse requis pour découvrir de telles optimisations possibles. L'angle heureux sur ce qu'optimisé le code managé est encore assez debuggable. Et qu'il y ait encore un rôle pour le programmeur C# pour écrire du code performant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X