2010-11-19 33 views
1

Implémentation actuelle: Attend que les valeurs parallelCount soient collectées, utilise ThreadPool pour traiter les valeurs, attende que tous les threads soient terminés, recollecte un autre jeu de valeurs, etc.C# - Renvoie les données du thread ThreadPool au thread principal

code:

private static int parallelCount = 5; 
private int taskIndex; 
private object[] paramObjects; 

// Each ThreadPool thread should access only one item of the array, 
// release object when done, to be used by another thread 
private object[] reusableObjects = new object[parallelCount];  

private void MultiThreadedGenerate(object paramObject) 
{ 
    paramObjects[taskIndex] = paramObject; 
    taskIndex++; 

    if (taskIndex == parallelCount) 
    { 
     MultiThreadedGenerate(); 

     // Reset 
     taskIndex = 0; 
    } 
} 

/* 
* Called when 'paramObjects' array gets filled 
*/ 
private void MultiThreadedGenerate() 
{ 
    int remainingToGenerate = paramObjects.Count; 

    resetEvent.Reset(); 

    for (int i = 0; i < paramObjects.Count; i++) 
    { 
     ThreadPool.QueueUserWorkItem(delegate(object obj) 
     { 
      try 
      { 
       int currentIndex = (int) obj;  

       Generate(currentIndex, paramObjects[currentIndex], reusableObjects[currentIndex]); 
      } 
      finally 
      { 
       if (Interlocked.Decrement(ref remainingToGenerate) == 0) 
       { 
        resetEvent.Set(); 
       } 
      } 
     }, i); 
    } 

    resetEvent.WaitOne();  
} 

J'ai vu des améliorations de performances significatives avec cette approche, mais il y a un certain nombre de questions à considérer:

[1] valeurs enCollectionneret la synchronisation à l'aide de resetEvent peut être évitée car il n'y a pas de dépendance entre les threads (ou l'ensemble actuel de valeurs avec l'ensemble de valeurs suivant). Je fais seulement ceci pour gérer l'accès à reusableObjects (quand un ensemble paramObjects est fait traitement, je sais que tous les objets dans réutilisableObjects sont libres, ainsi taskIndex est remis à zéro et chaque nouvelle tâche du prochain ensemble de valeurs aura son unique 'réutilisableObj ' travailler avec).

[2] Il n'y a pas de réelle connexion entre la taille de reusableObjects et le nombre de threads que le ThreadPool utilise. Je peux initialiser reusableObjects pour avoir 10 objets, et dire qu'en raison de certaines limitations, ThreadPool peut exécuter seulement 3 threads pour ma méthode MultiThreadedGenerate(), puis je gaspille de la mémoire.

Alors en se débarrassant de paramObjects, comment le code ci-dessus être affiné d'une manière qui dès qu'un thread termine son travail, ce thread retourne son taskIndex (ou reusableObj) il utilisé et n'a plus besoin de façon à devient disponible à la prochaine valeur. En outre, le code devrait créer un reUsableObject et l'ajouter à une collection seulement quand il y a une demande pour cela. Utiliser une file d'attente ici est-il une bonne idée?

Merci.

+0

Dans quelle version de .Net êtes-vous? –

+0

J'utilise .NET 3.5 – alhazen

Répondre

5

Il n'y a vraiment aucune raison de faire votre propre gestion manuelle des tâches et des tâches. Vous pouvez le restructurer en un modèle plus faiblement couplé en utilisant Task Parallel Library (et éventuellement System.Collections.Concurrent pour la collation des résultats).

Les performances pourraient être encore améliorées si vous n'avez pas besoin d'attendre un travail complet avant de passer à Task pour le traitement. La TPL est arrivée en .Net 4.0 mais était back-ported to .Net 3.5. Téléchargez here.

+0

+1 Je ne connaissais pas le port de retour, donc merci pour l'info. –

+0

@Brian - Je l'avais vu ref mais je ne l'ai pas retrouvé avant, c'est très utile s'il est bien caché. –