Performances / CIL [Résolu]

Signaler
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
-
Messages postés
2368
Date d'inscription
mardi 17 avril 2001
Statut
Modérateur
Dernière intervention
26 décembre 2007
-
Bonjour a tous,

J'ai envie de commencer la journée par une question de performance.
Soit un programme minimaliste qui crée un entier i et qui l'affiche par un Console.Writeline.
3 possibilités se proposent a nous.
La premiere :


int i = 1;
string a = i.ToString();
System.Console.WriteLine(a);

On passe donc par la création d'une string avant de l'afficher.
Code IL correspondant

.locals init ([0] int32 i, [1] string a)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s i
IL_0004: call instance string [mscorlib]System.Int32::ToString()
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: call void [mscorlib]System.Console::WriteLine(string)

Seconde solution, ne pas creer l'instance de string, mais afficher i de telle façon

System.Console.WriteLine(i.ToString());

Code IL :

.locals init ([0] int32 i)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldloca.s i
IL_0004: call instance string [mscorlib]System.Int32::ToString()
IL_0009: call void [mscorlib]System.Console::WriteLine(string)

Le code IL est sensiblement variable, mise a part qu'il n'y a qu'une variable locale de crée (je l'interprete ainsi, peut-etre que je me trompe) et qu'il n'y pas pas les opérations sur les piles. Cependant, une instance de string est créée quand meme.

Troisième solution, afficher i en formatant la chaine dans le Console.WriteLine

System.Console.WriteLine("{0}", i);

Code IL :

.locals init ([0] int32 i)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldstr "{0}"
IL_0007: ldloc.0
IL_0008: box [mscorlib]System.Int32
IL_000d: call void [mscorlib]System.Console::WriteLine(string, object)

Oh miracle, l'instance de string n'est plus créée, mais il y a cependant une opération de boxing, ce qui va revenir implicitement au même, non ? (allocation d'une instance de type reference, donc sur le tas.)

Ma question est donc, laquelle de ces 3 possibilités sera la moins gourmande en ressources / temps ? Ou laquelle est plus efficace ?

C'est clair que dans ce cas, cela n'a pas de grande importance, mais j'aimerais optimiser un code, et donc commencer par savoir dans quel cas il vaut mieux faire du boxing, ou alors créer des nouveaux objets, etc...
Je dirais qu'a choisir entre la premiere solution et la deuxieme, la deuxieme est plus performante. Mais sinon ... ?

Et n'hésitez pas a me corriger si je me suis trompé quelque part dans mon interpretation, je suis pas un expert en code IL (comme en C# d'ailleurs )

Mx

8 réponses

Messages postés
2368
Date d'inscription
mardi 17 avril 2001
Statut
Modérateur
Dernière intervention
26 décembre 2007
19
Je peux me tromper mais dans ce cas c'est normal

object o1 = null;

La tu affectes ta variables donc du coup elle est instancié.

par contre si tu fais ;

object o1;

puis dans le consctructeur tu l'initialises , tu n'auras pas les mêmes résultats

ESsayes et dis nous :)

::|The S@ib|::
MVP C#.NET
Messages postés
2368
Date d'inscription
mardi 17 avril 2001
Statut
Modérateur
Dernière intervention
26 décembre 2007
19
Dans ta troisième solution :

.locals init ([0] int32 i)
IL_0000: ldc.i4.1
IL_0001: stloc.0
IL_0002: ldstr "{0}" <= LOAD STRING :)
IL_0007: ldloc.0
IL_0008: box [mscorlib]System.Int32
IL_000d: call void [mscorlib]System.Console::WriteLine(string, object)

Dans ton cas , je suis a peu près sûr que la meilleure solution est la deuxième

::|The S@ib|::
MVP C#.NET
Messages postés
2368
Date d'inscription
mardi 17 avril 2001
Statut
Modérateur
Dernière intervention
26 décembre 2007
19
Je ne sais pas sur quoi tu bosses, mais as tu envisager une optimisation native ?

::|The S@ib|::
MVP C#.NET
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
<!--StartFragment -->En fait, je fais juste des tests d'applis Client/Serveur, mais ce ne sont que des applis perso pour apprendre. Et la je me suis posé la question d'optimisation du code (et de mon style de codage, en général).
Pour l'optimisation native, tu veux parler de la compilation avec ngen.exe ?

Autre petite question :
Je me suis toujours laissé dire qu'il vallait mieux instancier de nouveaux objets dans le constructeur de la classe plutot qu'a leur déclaration. J'ai toujours cru que ca rendait le code plus "propre". Et puis je trouvais ca plus lisible ;)
Mais prenons ce code :



object o1 = null;
object o2 = new object();

public
Test()
{
o1 = new object();
}

Le code IL généré est alors

IL_0002: stfld object CIL.Test::o1
IL_0007: ldarg.0
IL_0008: newobj instance void [mscorlib]System.Object::.ctor()
IL_000d: stfld object CIL.Test::o2
IL_0012: ldarg.0
IL_0013: call instance void [mscorlib]System.Object::.ctor()
IL_0018: ldarg.0
IL_0019: newobj instance void [mscorlib]System.Object::.ctor()
IL_001e: stfld object CIL.Test::o1
IL_0023: ret

Les lignes IL_0002 et IL_001e, correspondant a l'objet o1, sont redondantes. si on ajoute la ligne IL_0019 pour l'appel du constructeur de la class object, on a 3 instructions, contre 2 pour l'objet o2 (IL_0008 et IL_000d).
Ca voudrait donc dire qu'il vaut mieux dans ce cas, créer l'objet a sa déclaration ?

Merci pour tes réponses

Mx
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
Oui, tu as raison, si j'enleve le = null; ca change le résultat, et cela devient identique a l'object o2 ;

Il est quand meme pourtant plus "propre" de le déclarer null, ou alors
en .net cela ne pose pas de probleme si la varible n'est pas
initialisée a sa déclaration ?

Exemple, pout les string, je les déclare toujours avec la valeur String.Empty. Es-ce reellement necessaire ?



Merci encore :)



Mx
Messages postés
2368
Date d'inscription
mardi 17 avril 2001
Statut
Modérateur
Dernière intervention
26 décembre 2007
19
non ce n'est pas nécessaire de le mettre a empty a partir du moment ou tu l'instancie avant de t'en servir. Je pensequ'il faut que tu initialises tes variables qu'a partir du moment ou tu en as besoin et inversement quand tu n'en a plus besoin. Ca t'evite d'avoir des fuites de mémoires mais aussi des espaces qui resident et qui ne servent a rien.

Moi je suis plus de l'école :

object o;

Puis l'initialisation si besoin est plus tard

D'ailleur il me semble que le designer lors de la génération des forms en fait tout autant, il déclare les variables mais les instancies que dans le initialize components, certes qui est appelé dans le constructeur.

::|The S@ib|::
MVP C#.NET
Messages postés
3466
Date d'inscription
lundi 16 octobre 2000
Statut
Modérateur
Dernière intervention
30 octobre 2008
46
Tu as raison.

Tu m'as bien éclairé sur ce sujet


Mx
Messages postés
2368
Date d'inscription
mardi 17 avril 2001
Statut
Modérateur
Dernière intervention
26 décembre 2007
19
Deriens

::|The S@ib|::
MVP C#.NET