Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Atteint de JavaScriptite Aiguë [Cyril Durand]

Expert ASP.net Ajax et WCF, Cyril Durand parle dans son blog de point techniques sur ASP.net, ASP.net Ajax, JavaScript, WCF et .net en général. Cyril est également consultant indépendant, n'hésitez pas à le contacter pour de l'assistance sur vos projets

Actualités

  • Blog de Cyril DURAND, passionné de JavaScript, Ajax, ASP.net et tout ce qui touche au developpement Web Client-Side.

    N'hésitez pas à me contacter pour vos projets .net : architecture, accompagnement, formation, ...

    View Cyril Durand's profile on LinkedIn
    hit counters


    Expertise Commerce server et BizTalk

.net 4 et Lazy-loading thread-safe : un nouveau type bien pratique

.net 4.0 a introduit plein de petites nouveautés au sein de mscorlib : l’assembly principale du framework .net.

L’une des nouveautés que j’aime bien et le type Lazy. Ce type permet de faire du lazy-loading simplement et permet surtout de le faire de façon thread-safe.

Tout d’abord, revenons sur le principe de lazy-loading. Il s’agit d’un design pattern permettant le chargement ou la création de la valeur d’une propriété à la demande.

Imaginons que vous disposez d’une classe Pouet qui comporte plusieurs propriétés dont la propriété HeavyProperty. Comme son nom l’indique, cette propriété est très couteuse, on va donc vouloir créer la valeur seulement lorsque l’on en a vraiment besoin.

Le code ci-dessous est un exemple d’une propriété en lazy-loading :

public class Pouet
{
    private HeavyObject _heavyProperty;
    public HeavyObject HeavyProperty {
        get {
            if (this._heavyProperty != null) {
                this._heavyProperty = new HeavyObject();
            }
            return this._heavyProperty;
        }
    }
}

Bien que fonctionnel, ce code n’est pas parfait : il n’est pas thread safe. Si 2 threads accèdent simultanément à la propriété, alors le constructeur de HeavyObject peut être appelé deux fois.

Souvent, ce n’est pas gênant. Si l’instance de Pouet est utilisé par un seul thread, il est alors inutile de les rendre thread-safe. De plus, si la valeur de la propriété n’a pas besoin d’être unique et si l’initialisation de l’objet n’est pas très couteux, inutile de sortir l’artillerie lourde. Dans les autres cas, ce comportement peut poser bien des soucis.

Avec .net 3.5, on pouvait utiliser le mot clé lock ou la classe Monitor. Personnellement, je préfère utiliser la classe Monitor, cela permet de définir un timeout et ainsi éviter les deadlock. En interne, le mot clé lock utilise également la classe Monitor.

Au final, une propriété en lazy-loading thread-safe s’écrit comme ca en .net 3.5 :

public class Pouet
{
    private Object _heavyPropertyLock = new Object(); 
    private HeavyObject _heavyProperty;
    public HeavyObject HeavyProperty {
        get {
            if (this._heavyProperty == null) {
                if (!Monitor.TryEnter(this._heavyPropertyLock, 4000)) {
                    throw new Exception("can't acquire lock"); 
                }
                try {
                    // double check. Check if another thread didn't create the HeavyObject 
                    // while this thread was waiting for aquiring the lock object
                    if (this._heavyProperty == null) {
                        this._heavyProperty = new HeavyObject();
                    }
                }
                finally {
                    Monitor.Exit(this._heavyPropertyLock); 
                }
            }
            return this._heavyProperty;
        }
    }
}

Comme on peut le voir, cela devient relativement lourd.

Avec .net 4.0, il existe le type Lazy qui va permettre de simplifier tout ça. Voici le même code que ci-dessus avec le type Lazy :

public class Pouet
{
    private Lazy<HeavyObject> _heavyProperty = new Lazy<HeavyObject>(() => new HeavyObject());
    public HeavyObject HeavyProperty {
        get {
            return this._heavyProperty.Value;
        }
    }
}

Plutot simple non ?

Cela fonctionne ainsi. Dans l’exemple ci-dessus, le constructeur du type Lazy prend un Func<T>. Ce Func<T> doit retourner une instance de l’objet que l’on veut initialiser. Lors du premier accès à la propriété Value, le type Lazy va executer le Func<T> tout en faisant en s’occupant de la synchronisation des threads afin d’éviter que 2 threads initialisent simultanément l’objet.

A noter qu’il existe plusieurs constructeurs. Il existe un constructeur vide, dans ce cas, le type Lazy va initialiser le type T à l’aide de son constructeur par défaut.

Un autre constructeur prend en entrée un LazyThreadSafetyMode.

image

Ce paramètre permet d’indiquer la façon dont le type Lazy doit gérer la concurrence de thread. Il s’agit d’une enum qui a 3 valeurs :

  • None                              : le type Lazy ne garantit pas que l’initialisation soit effectuée qu’une seule fois
  • PublicationOnly                : Plusieurs threads peuvent initialiser l’objet. Le premier thread qui termine l’initialisation définit la propriété Value, tous les threads utiliseront cette valeur.
  • ExecutionAndPublication   : Seul un thread peut initialiser l’objet. Valeur par défaut.

Connaissiez-vous le type Lazy<T> ? L’aviez-vous déjà utilisé ?

Posted: dimanche 7 août 2011 20:27 par cyril
Classé sous : ,
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

Graveen a dit :

Interessant, merci Cyril, j'ai justement quelques codes à base de lock() que je voulais revoir !

# août 7, 2011 23:00
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Nouveau blog en anglais / New blog in english ! par Le blog de Patrick [MVP SharePoint] le il y a 2 heures et 48 minutes

- [ #Yammer ] From Mailbox to Yammer and back / De votre messagerie vers Yammer et retour ! par Le blog de Patrick [MVP SharePoint] le 09-15-2014, 11:31

- [ #Office 365 ] New service settings panel / Nouveau panneau de paramétrage des services par Le blog de Patrick [MVP SharePoint] le 09-11-2014, 08:50

- Problème de déploiement pour une démo SharePoint/TFS? par Blog de Jérémy Jeanson le 09-10-2014, 21:52

- [ #Office365 ] Delve first impressions / Premières impressions sur Delve par Le blog de Patrick [MVP SharePoint] le 09-09-2014, 16:57

- [ #Office365 ] How to change Administration console language ? / Comment changer la langue de la console d’administration ? par Le blog de Patrick [MVP SharePoint] le 09-09-2014, 08:25

- [ #SharePoint 2013 ] Suppression de bases de données en état “Pas de Réponse” par Le blog de Patrick [MVP SharePoint] le 09-04-2014, 14:10

- Changer l’adresse d’une ferme Office Web Apps associée à SharePoint par Blog de Jérémy Jeanson le 09-01-2014, 22:21

- Une ferme #SharePoint 2013 dans @Azure en quelques clics (1ère partie) ! par Le blog de Patrick [MVP SharePoint] le 08-28-2014, 18:52

- SharePoint 2013: Préparation de la migration - Création des site Templates dans 2010 et 2013 par Blog Technique de Romelard Fabrice le 08-20-2014, 16:31