Astuces DotNet (Sébastien Courtois)

28/01/2010

[.NET] Le mot clé sealed sur une classe permet-il permettre de gagner en performance ?

Filed under: .NET, Débutant, Intermediaire, Optimisation — Étiquettes : , , , , , — sebastiencourtois @ 00:19

Voici la question que Wilfried Woivre (MSP ainsi que “Ask The Expert” sur Azure aux prochains Tech Days 2010).

Ma première réponse a été… “J’en sais rien” :). En effet, le mot clé sealed a toujours été, pour moi, utilisé pour des design OO spécifiques (type création de framework public …) où l’idée est d’interdire l’extension d’une classe (la fonction première du mot clé sealed). J’ai donc dit que je pensais que ce n’était pas le cas ni le rôle de ce mot clé.

Quelque temps plus tard, je me retrouve à lire un chapitre sur l’optimisation de code .NET dans lequel le mot clé “sealed” == performance. J’ai donc décidé de faire le benchmark suivant :

   public class ClassA
   {
       public void Method1() { }
   }

   public sealed class ClassASealed
   {
       public void Method1() { }
   }

   public class ClassAVirtual
   {
       public virtual void Method1() { }
   }

    
class Program
{
    static void Main(string[] args)
    {
        ClassA ca = new ClassA();
        ClassASealed cas = new ClassASealed();
        ClassAVirtual cav = new ClassAVirtual();

        Stopwatch swca = new Stopwatch();
        Stopwatch swcas = new Stopwatch();
        Stopwatch swcav = new Stopwatch();
        for (int i = 0; i < 10000000; i++)
        {
            swca.Start();
            ca.Method1();
            swca.Stop();

            swcas.Start();
            cas.Method1();
            swcas.Stop();

            swcav.Start();
            cav.Method1();
            swcav.Stop();
        }

        Console.WriteLine("ClassA  : " + swca.Elapsed);
        Console.WriteLine("ClassAS : " + swcas.Elapsed);
        Console.WriteLine("ClassAV : " + swcav.Elapsed);
        Console.WriteLine("Finish");
        Console.ReadLine();
    }
}

On teste, ici, le temps d’appel des méthodes en faisant 1 000 000 d’appels. On trouve les résultats suivants :

  • Classe Normale : 22.8844652 secondes
  • Classe Sealed : 22.8523417 secondes
  • Classe Normale avec une méthode virtuelle : 23.0062174 secondes

Premier constat : Le mot clé sealed nous permet de gagner environ 1 pour 1000 en performance.

Deuxième constat : la méthode virtuelle semble faire perdre aussi des performances ( 5 ou 6 pour 1000).

Pourquoi ces écarts ?

1°)Parlons tous d’abord de l’écart normale/sealed : Au niveau du code IL, il n’y a que le sealed de différence :

.class public auto ansi beforefieldinit ClassAVirtual
.class public auto ansi sealed beforefieldinit ClassASealed

L’optimisation à lieu au niveau du Runtime. En effet, sachant que la classe est scellé, le runtime peut faire un appel direct à la méthode (dans certains cas, exécuter le code sans faire d’appel).

2°) Pour la différence méthode classique /méthode virtuelle :

.method public hidebysig instance void Method1() cil managed
.method public hidebysig newslot virtual instance void Method1() cil managed

Le virtual ici oblige le runtime a créer une table d’appel pour cette méthode virtuelle dans laquelle seront contenu les méthodes des classes dérivées qui surchargeront cette méthode. Par conséquent, un appel à cette méthode est un appel ‘virtuel’ de méthode qui doit aller chercher dans cette table pour trouver la bonne méthode à appelé. Même si dans notre cas, la table ne contient qu’un seul élément, il y a tout de même un coût supplémentaire par rapport à un appel classique (accès à la table,recherche dans la table …)

Conclusion

Effectivement, le fait de mettre rendre classe ‘sealed’ permet de gagner des performances. Toutefois les performances sont tellement faible que dans 95 % des cas (disons : les applications non temps réel ou ne travaillant pas avec des énormes volumes de données), ces gains sont négligeables et il sera plus judicieux de voir s’il n’y a pas des optimisations à faire au niveau du code ou de l’architecture du projet.

Publicités

11/03/2009

Erreur 404 lors d’un Debug d’un projet ASP.NET en utilisant “ASP.NET Development Server” sur localhost pour Vista

Filed under: Hors Catégorie, Intermediaire — Étiquettes : , , , , , , , , , — sebastiencourtois @ 12:10

Bon, le titre est un peu long pour un post aussi court mais il s’agit des mots clés que j’ai mis dans Google pour résoudre un bug qui m’empêchait de bosser depuis quelques temps (d’où le peu de post sur ce site récemment).

Lorsque je travaillais sur un projet ASP.NET (Silverlight ou autres), je me prenais systématiquement une page d’erreur 404 au lancement du débogage. J’étais sûr à 99.99 % que cela ne venait pas de mes projets car je les utilisait depuis plusieurs mois sans problème.

Après de longues recherches (car très peu de posts parlent de ce problème), j’ai trouvé le blog de Accidental Technologist et sur celui de Information for Technology qui indiquent que cela vient d’un bug/problème sous Vista avec les adresses IPv6 pour localhost.

La Solution :

Modifier le fichier hosts dans le répertoire C:\Windows\System32\drivers\etc.

Remplacer

::1             localhost

par

:::1             localhost  (si vous êtes en IPv6)

127.0.0.1             localhost  (si vous êtes en IPv4)

 

Cette solution m’a permis de visualiser ma page sous IE.

L’explication :

Je n’ai pas trouvé d’explication exacte quant à ce problème mais je vais vous donner ma reflexion :

en IPv4, l’adresse localhost est 127.0.0.1.

Avec l’arrivée de l’IPv6, on obtient l’adresse localhost suivante : 0:0:0:0:0:0:0:1

Or d’après la norme IpV6, on peut supprimer les 0 quand il y en a : 0:0:0:0:0:0:0:1 => :::::::1  (7 caractères ‘:’ et un caractère ‘1’)

Toujours d’après cette norme. Si plusieurs ‘:’ se suivent, on peut les remplacer par un seul au début et un seul à la fin donc  :::::::1 => ::1

Lorsque l’on tape dans IE, la chaine suivante : http://[::1]/ .On retombe bien sur la page localhost.

Deux questions me viennent donc à l’esprit :

1°) Pourquoi rajouter un ‘:’ dans le fichier host (Sachant que d’après la norme :  ::1 == :::1 == 0:0:0:0:0:0:0:1 et que ::1 est bien localhost dans la norme) ?

2°) Que s’est-il passé sur mon ordinateur pour que ce problème apparaisse alors que mes projets fonctionnaient correctement à l’origine (Problème détecté la première fois le 10/03/09) ?

Si vous arrivez à répondre à l’une de ces questions, n’hésitez pas à poster en commentaire :). Je continue à chercher de mon coté et je mettrais à jour ce post si je trouve.

EDIT 11/03/09 12h27 : Apparemment pas le seul dans ce cas, car j’ai reçu ce mail  il y a quelques minutes (venant un Microsoft Student Partner dont je vais taire le nom 🙂 ) :  “je voulais savoir si tu avais déjà eu des problèmes avec Cassini, parce que là il ne veut plus m’afficher aucune page que ce soit sur un site ASP.Net MVC, ou ASP.Net classique.”.

EDIT 11/03/09 15h00 : Il semble qu’une mise à jour de Windows Defender aurait modifier le fichier hosts entrainant des bugs sur les sites ‘localhost’

03/03/2009

Débogage d’un processus .NET lancé par un processus externe

Filed under: .NET, Débutant — Étiquettes : , , , , , — sebastiencourtois @ 21:46

Au cours de mes temps libre, j’ai eu l’occasion de participer à un concours de programmation (TopCoder). Dans une des catégories, je devais créer un exécutable (.NET) qui était lancé dans un processus Java (fichier exécutable .jar).

Le soucis est que je voudrais pouvoir utiliser toutes les fonctionnalités de débogage du code source pendant l’exécution de mon programme.

Première solution : Lancer le processus externe après la compilation de l’exécutable :

En modifiant le projet .NET, on peut choisir de lancer un autre processus lors de la fin de la compilation de l’exécutable.

Pour accéder à ce menu : Clic droit sur le projet > Properties > Onglet “Debug”

Vous pouvez choisir entre :

  1. Ouvrir le projet courant et attacher le debugger dessus (Comportement par défaut)
  2. Ouvrir un autre exécutable et attacher le debugger sur le projet courant
  3. Ouvrir un navigateur Web sur une adresse définie (pour le débogage ASP.NET)

J’ai beaucoup utilisé la deuxième option lors d’Imagine Cup l’an passé (sur Project Hoshimi). Toutefois, cette option n’accepte que les exécutables avec une extension .exe (donc ni .bat ni .jar :().

Deuxième solution : Attacher un processus lancé à Visual Studio

Visual Studio permet de débogage n’importe quel processus lancé sur la machine.

Pour cela, il suffit d’aller dans le menu Debug > Attach To Process.

attachtoProcess

Une fenêtre apparait permettant de choisir le processus voulu parmi ceux tournant sur la machine.

blogattachtoprocesswindow

Une fois le processus sélectionné, vous avez deux possibilités :

  1. Vous possédez le code source de l’application : Dans ce cas, vous serez à même de déboguer en plaçant des points d’arrêts au sein du code source
  2. Vous ne possédez pas le code source : Dans ce cas, vous pourrez seulement trapper les exceptions sortants de l’applications et voir le code “désassemblé” (MSIL pour les codes managés / Assembleur pour les codes natifs).

Cette méthode est simple et pratique pour déboguer des applications tournant en boucle comme des services.

Dans mon cas, l’exécution de mon code était un algorithme très court. Je n’avais pas le temps d’aller chercher mon processus dans la fenêtre “Attach To Process” pour avoir accès au débuggeur.

Troisième solution : Attacher le debugger Visual Studio à un processus par code

Il faut donc trouver un moyen d’attacher le debugger Visual Studio au début du code de mon processus.

Une petite recherche sur MSDN m’a permis de trouver la classe System.Diagnostics.Debugger qui permet d’interagir avec le debugger Visual Studio au travers de mon code.

Cette classe présente assez peu de méthodes mais permet tout de même de poser des points d’arrêt, de loguer certaines informations et d’attacher un débugger.

La méthode Launch() est la méthode permettant d’attacher le debugger au processus courant. Elle est bloquante et entraine l’apparition d’une fenêtre demandant le debugger à utiliser.

Blog3

Il y a, en général, le choix d’ouvrir une nouvelle instance (dans ce cas, le débogage se fera avec le code MSIL/ASM) ou d’attacher le processus à un Visual Studio déjà ouvert (si possible contenant le code source du processus à déboguer). Je n’ai pas trouvé de moyen de supprimer cette étape de sélection par le code.

Une fois le debugger sélectionné, la phase de débogage se fait de la même manière que pour une application classique. Il est possible de vérifier si le processus est attaché à un debugger grâce à la propriété Debugger.IsAttached.

La méthode Break() permet de poser un point d’arrêt depuis le code source.

Créez un site Web ou un blog gratuitement sur WordPress.com.

%d blogueurs aiment cette page :