Question Le compilateur C # n'optimise pas les conversions inutiles


Il y a quelques jours, en écrivant une réponse pour cette question ici, en débordement, j'ai été un peu surpris par le compilateur C #, qui ne faisait pas ce que je m'attendais à faire. Regardez ce qui suit pour coder des extraits:

Premier:

object[] array = new object[1];

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

Seconde:

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 la conversion vers ICollection <objet>. L'objet [] implémentant explicitement l'interface ICollection <object>, je m'attendais à ce que les deux fragments soient compilés dans le même IL et soient donc identiques. Cependant, lors de l'exécution de tests de performance sur ces derniers, j'ai remarqué que ce dernier était environ six fois plus rapide que le précédent.

Après avoir comparé l'IL des deux extraits, j'ai remarqué que les deux méthodes étaient identiques, à l'exception d'un le castclass Instruction IL dans le premier extrait.

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


30
2018-02-07 12:26


origine


Réponses:


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


32
2018-02-07 15:21



C'est une approximation approximative, mais je pense que cela concerne la relation entre Array et son IEnumerable générique.

Dans le .NET Framework version 2.0, le   La classe Array implémente la   System.Collections.Generic.IList,   System.Collections.Generic.ICollection,   et   System.Collections.Generic.IEnumerable   interfaces génériques. le   les implémentations sont fournies aux tableaux   au moment de l'exécution, et ne sont donc pas   visible à la documentation   outils. En conséquence, le générique   les interfaces n'apparaissent pas dans le   Syntaxe de déclaration pour le tableau   classe, et il n'y a pas de référence   sujets pour les membres d'interface qui sont   accessible uniquement en jetant un tableau à   le type d'interface générique (explicite   implémentations d'interface). La clé   chose à savoir quand vous lancez un   tableau à l'une de ces interfaces est   que les membres qui ajoutent, insèrent ou   supprimer des éléments jeter   NotSupportedException.

Voir Article MSDN.

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


4
2018-02-07 12:56



Cela ne ressemble pas à plus d'une occasion manquée dans le compilateur pour supprimer la distribution. Cela fonctionnera si vous écrivez comme ceci:

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

ce qui suggère que cela devient trop conservateur car les moulages peuvent lancer des exceptions. Cependant, cela fonctionne quand vous lancez sur ICollection non générique. Je concluais qu'ils l'ont simplement ignoré.

Il y a un problème d'optimisation plus important au travail ici, le compilateur JIT n'applique pas l'optimisation de levage invariant de boucle. Il aurait dû réécrire 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);
}

Quelle est une optimisation standard dans le générateur de code C / C ++ par exemple. Néanmoins, l'optimiseur JIT ne peut pas graver beaucoup de cycles sur le type d'analyse nécessaire pour découvrir de telles optimisations possibles. Le point de vue positif à cet égard est que le code géré optimisé est encore tout à fait débogeable. Et que le programmeur C # ait encore un rôle à jouer pour écrire du code performant.


2
2018-02-07 15:50