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

- SharePoint : Bug sur la gestion des permissions et la synchronisation Office par Blog Technique de Romelard Fabrice le 07-10-2014, 11:35

- SharePoint 2007 : La gestion des permissions pour les Workflows par Blog Technique de Romelard Fabrice le 07-08-2014, 11:27

- TypeMock: mock everything! par Fathi Bellahcene le 07-07-2014, 17:06

- Coding is like Read par Aurélien GALTIER le 07-01-2014, 15:30

- Mes vidéos autour des nouveautés VS 2013 par Fathi Bellahcene le 06-30-2014, 20:52

- Recherche un passionné .NET par Tkfé le 06-16-2014, 12:22

- [CodePlex] Projet KISS Workflow Foundation lancé par Blog de Jérémy Jeanson le 06-08-2014, 22:25

- Etes-vous yOS compatible ? (3/3) : la feuille de route par Le blog de Patrick [MVP SharePoint] le 06-06-2014, 00:30

- [MSDN] Utiliser l'approche Contract First avec Workflow Foundation 4.5 par Blog de Jérémy Jeanson le 06-05-2014, 21:19

- [ #ESPC14 ] TH10 Moving mountains with SharePoint ! par Le blog de Patrick [MVP SharePoint] le 06-01-2014, 11:30