38 votes

Le compilateur C# supprime-t-il un if qui encapsule un debug.writeline ?

J'ai un morceau de code comme celui-ci :

if (state != "Ok")
{
     Debug.WriteLine($"Error occured: {state}, {moreInfo}");
}

Est-ce que le compilateur optimise cela si je fais un release build ? Ou bien l'évaluation est-elle maintenue et coûte-t-elle du temps de traitement ?

26 votes

Utilisez le Debug.WriteLineIf método.

4 votes

Remarque : Il n'existe pas de compilateur C# unique. Il existe plusieurs compilateurs C#, dont chacun a été publié dans de nombreuses versions. La spécification C# ne prévoit que très peu d'optimisations obligatoires (voire aucune), de sorte que votre réponse ne pourra jamais concerner qu'un compilateur particulier et une version particulière.

48voto

Patrick Hofman Points 22166

Oui, c'est le cas, au moins pour le Debug appel. Je ne vois pas ici si le compilateur JIT a également supprimé l'évaluation de l'élément if mais je suppose que c'est le cas puisque l'équation n'a pas d'effets secondaires.

Cependant, il est préférable de le garder en sécurité en appelant Debug.WriteLineIf qui ne dépend pas du compilateur JIT pour supprimer l'évaluation.

Pour être complet, la preuve que le compilateur supprime l'option Debug.WriteLine .


Le code dans le Release build :

.method public hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       17 (0x11)
  .maxstack  8
  IL_0000:  call       string [mscorlib]System.Console::ReadLine()
  IL_0005:  ldstr      "Ok"
  IL_000a:  call       bool [mscorlib]System.String::op_Inequality(string,
                                                                   string)
  IL_000f:  pop
  IL_0010:  ret
} // end of method Program::Main

Code dans la version Debug :

.method public hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       42 (0x2a)
  .maxstack  2
  .locals init ([0] string state,
           [1] bool V_1)
  IL_0000:  nop
  IL_0001:  call       string [mscorlib]System.Console::ReadLine()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldstr      "Ok"
  IL_000d:  call       bool [mscorlib]System.String::op_Inequality(string,
                                                                   string)
  IL_0012:  stloc.1
  IL_0013:  ldloc.1
  IL_0014:  brfalse.s  IL_0029
  IL_0016:  nop
  IL_0017:  ldstr      "Error occured: {0}"
  IL_001c:  ldloc.0
  IL_001d:  call       string [mscorlib]System.String::Format(string,
                                                              object)
  IL_0022:  call       void [System]System.Diagnostics.Debug::WriteLine(string)
  IL_0027:  nop
  IL_0028:  nop
  IL_0029:  ret
} // end of method Program::Main

Comme vous le voyez, le mode Release n'a pas d'appel à Debug.WriteLine alors que le mode Debug le fait.

0 votes

Existe-t-il un moyen de vérifier que le JIT le supprime bien ?

4 votes

Pas à ce que je sache. C'est une boîte noire.

0 votes

Je vois. Merci. Belle réponse.

15voto

Abion47 Points 6101

Desde La page de MSDN sur la classe Debug :

Si vous utilisez des méthodes dans le Debug pour imprimer des informations de débogage et vérifier votre logique à l'aide d'assertions, vous pouvez rendre votre code plus robuste sans nuire aux performances et à la taille du code de votre produit d'expédition.

...

El ConditionalAttribute est appliqué aux méthodes de Debug . Les compilateurs qui prennent en charge ConditionalAttribute ignorent les appels à ces méthodes, sauf si "DEBUG" est défini comme un symbole de compilation conditionnelle.

Comme vous pouvez le voir, le compilateur omettra tout appel à Debug sur les versions non déboguées. Cependant, cela n'empêchera pas le programme de vérifier votre instruction if. Si vous voulez que le compilateur ignore également l'instruction if, vous pouvez utiliser une balise directive du préprocesseur pour entourer le bloc entier comme ceci :

#if DEBUG
if (state != "Ok")
{
    Debug.WriteLine($"Error occured: {state}, {moreInfo}");
}
#endif

5voto

usr Points 74796

Le compilateur C# est tenu par les spécifications du langage de supprimer l'attribut Debug appelez y l'évaluation de ses arguments.

Si le JIT .NET était un JIT sophistiqué, il déterminerait que l'appel de la méthode string n'a pas d'effet secondaire et peut être supprimé. Le JIT .NET n'est pas très sophistiqué, il y a donc une chance qu'il appelle encore cette méthode. C'est ce que nous allons voir.

Compilez le programme en mode Release, décompilez-le et exécutez-le en x64 sur 4.6.2 sans que le débogueur ne supprime les optimisations.

    static void Main()
    {
        var state = GetState();
        if (state != "Ok")
        {
            Debug.WriteLine(state);
        }
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    static string GetState()
    {
        return "x";
    }

Le compilateur C# a laissé intact l'appel à l'inégalité des chaînes de caractères :

enter image description here

enter image description here

Je ne suis pas sûr que la spécification permette de l'optimiser car il pourrait s'agir d'une méthode à effet secondaire. Je ne sais pas ce que le compilateur est autorisé à supposer à ce sujet.

Notre fantastique JIT n'a pas non plus supprimé l'appel :

enter image description here

(1) est le GetState() et (2) est string.!= .


Utilice Debug.WriteLineIf parce que :

17.4.2.1 Méthodes conditionnelles Une méthode décorée avec l'attribut Conditional est une méthode conditionnelle. L'attribut Conditionnel indique une condition en testant un symbole de compilation conditionnelle. Les appels à une méthode conditionnelle sont inclus ou omis selon que ce symbole est défini ou non au moment de l'appel. Si le symbole est défini, l'appel est inclus ; sinon, l'appel (y compris l'évaluation du récepteur et des paramètres de l'appel) est omis.

1 votes

Pourriez-vous indiquer où, dans les spécifications, il est indiqué que Debug.X les appels doivent être supprimés ?

0 votes

@JeroenVannevel J'ai ajouté cela.

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