2011-08-29 3 views
1

Comment configurer Unity de manière à ce qu'une classe puisse s'initialiser de manière asynchrone sans bloquer la charge des autres modules (en bloquant uniquement les autres types qui ont explicitement besoin d'une instance du type asynch)? Le type de classes que je pense sont des caches de données de référence qui tirent un instantané des données fréquemment utilisées de la base de données, et j'ai besoin de terminer le précâblage avant de laisser d'autres modules y accéder (si les demandes sont bloquées dans ma classe I tiendra rapidement le thread principal et bloquera tous les autres modules de l'initialisation). Cela devient plus important que j'ai plusieurs telles classes de données de référenceComment configurer Unity pour l'initialisation asynchrone des types/modules

À titre d'exemple, que j'ai une classe comme ceci:

public class ProductCache{ 

    public ProductCache(){} 

    public Initialize(){ 
     // a very slow DB call to fetch frequently used products 
     Thread.Sleep(30*1000); 
    } 

    public Product FindProduct(string productDescription){ 
     /* check cache, if not there try the db */ 
    } 
} 

Si j'appelle Initialize du constructeur je bloquer le thread qui l'invoque (depuis Unity) pendant 30 secondes, m'empêchant de créer d'autres classes (similaires) en parallèle. Si je place simplement la tâche sur le pool de threads, Unity arrivera au point où une autre classe qui a besoin de mon cache de produit exécute son code d'initialisation, et accède alors aux structures de données qui ne sont pas encore complètement initialisées (dans ce cas dans un défaut de cache et un appel à la db pour aller chercher le produit, et il pourrait y avoir beaucoup de demandes en 30 secondes)

grâce Oskar

+0

pouvez-vous fournir du code, c'est la structure de la classe que vous initialisez? – onof

+0

a ajouté un petit exemple – Oskar

Répondre

1

Vous devez faire une liste des tâches en cours d'exécution, exécutez les en parallèle et utilisez Task.WaitAll() pour les attendre avant de continuer.

Dans .Net 4, cela devrait fonctionner, et la gestion des erreurs est facile:

public void InitializeAll() 
{ 
    List<Task> initTasks = new List<Task>(); 

    ProductCache productCache = new ProductCache(); 
    SomeOtherCache someOtherCache = new SomeOtherCache(); 

    initTasks.Add(Task.Factory.StartNew(() => productCache.Initialize())); 
    initTasks.Add(Task.Factory.StartNew(() => someOtherCache.Initialize())); 

    try 
    { 
     Task.WaitAll(initTasks.ToArray()); 
    } 
    catch (AggregateException ex) 
    { 
     Console.WriteLine("Oh dear!"); 
    } 
} 

Dans la vieille école .Net, essayez ceci. J'ai supposé que vous utilisez une interface pour chaque objet initialisable, et j'ai omis la gestion des erreurs:

public void InitializeAll(IEnumerable<IInitializable> initializeUs) 
{ 
    List<WaitHandle> handles = new List<WaitHandle>(); 

    foreach(IInitializable init in initializeUs) 
    { 
     // Make a copy of the reference in the local scope 
     IInitializable temp = init; 

     ManualResetEvent done = new ManualResetEvent(false); 
     handles.Add(done); 

     ThreadPool.QueueUserWorkItem(delegate 
     { 
      try 
      { 
       temp.Initialize(); 
      } 
      finally 
      { 
       done.Set(); 
      } 
     }); 
    } 

    // Wait for all the handles to be set 
    WaitHandle.WaitAll(handles.ToArray()); 
} 
+0

Oui, cela résout le problème. Je suppose que j'espérais quelque chose dans Unity (disons un attribut pour marquer des composants avec) qui déclencherait ce comportement. Il serait également capable d'utiliser les dépendances du module pour s'assurer que toutes les dépendances sont comptabilisées correctement. – Oskar

+0

Je vois ce que vous voulez dire. Vous pouvez utiliser le code ci-dessus pendant l'initialisation du module pour enregistrer les instances des types en parallèle, ce qui devrait gérer l'injection de dépendance. Cependant, vous pourriez rencontrer des problèmes de dépendances entre les différents types. –

Questions connexes