1

Pourquoi dois-je obtenir des résultats différents avec les éléments suivants aux sections de codeThreadLocal agrégations et des tâches Bibliothèque parallèle

Exemple de code 1

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Threading; 

namespace ThreadLocalTasks 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 

      ThreadLocal<int> aggregrations = new ThreadLocal<int>(); 
      Task<int>[] tasks = new Task<int>[10]; 

      for (int i = 0; i < tasks.Length; i++) 
      { 
       aggregrations.Value = 0; 
       int tempi = i; 
       tasks[tempi] = new Task<int>(() => 
       { 
        int temp = 0; 
        for (int j = 1; j <= 3; j++) 
        { 
         temp += j; 
        } 
        aggregrations.Value = temp; 
        return aggregrations.Value; 
       }); 

      } 

      tasks.ToList().ForEach(x => { 
       x.Start(); 
      }); 

      Task.WaitAll(tasks); 

      int sum = 0; 

      tasks.ToList().ForEach(x => 
      { 
       sum += x.Result; 
      }); 

      Console.WriteLine("Sum: {0}", sum); 

      Console.WriteLine("Press any key to quit.."); 
      Console.ReadKey(); 
     } 
    } 
} 

Exemple 2

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Threading; 

namespace ThreadLocalTasks 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 

      ThreadLocal<int> aggregrations = new ThreadLocal<int>(); 
      Task<int>[] tasks = new Task<int>[10]; 

      for (int i = 0; i < tasks.Length; i++) 
      { 
       aggregrations.Value = 0; 
       int tempi = i; 
       tasks[tempi] = new Task<int>(() => 
       { 
        for (int j = 1; j <= 3; j++) 
        { 
         aggregrations.Value += j; 
        } 
        return aggregrations.Value; 
       }); 

      } 

      tasks.ToList().ForEach(x => { 
       x.Start(); 
      }); 

      Task.WaitAll(tasks); 

      int sum = 0; 

      tasks.ToList().ForEach(x => 
      { 
       sum += x.Result; 
      }); 

      Console.WriteLine("Sum: {0}", sum); 

      Console.WriteLine("Press any key to quit.."); 
      Console.ReadKey(); 
     } 
    } 
} 

Répondre

1

Pourquoi êtes-vous même essayer utiliser ThreadLocal de stockage ici au lieu de simplement une variable locale dans la tâche? La bibliothèque Task Parallel peut très bien réutiliser un thread pour exécuter plusieurs tâches et votre stockage local de threads sera écrasé. Dans le premier exemple, il pourrait fonctionner puisque vous n'êtes pas réinitialiser chaque fois qu'un fil est réutilisé, mais ce serait mieux:

for (int i = 0; i < tasks.Length; i++) 
     { 
      tasks[i] = new Task<int>(() => 
      { 
       int sum = 0; 
       for (int j = 1; j <= 3; j++) 
       { 
        sum += j; 
       } 
       return sum; 
      }); 

     } 

Explication de ce que votre code ne fait:

En vous premier exemple, vous initialisez une seule valeur locale de thread à 0 sur le thread de démarrage, mais vous le faites plusieurs fois (clairement pas ce que vous vouliez en mettant l'initialisation dans la boucle for - bug # 1). Vous accumulez dans une variable task-local ce qui est bon mais vous remplacez la valeur locale du thread par le résultat même si cette valeur locale peut être partagée entre plusieurs tâches exécutées séquentiellement (par exemple un thread par cœur) - bug # 2. Cela entraînera certaines tâches à partager la même valeur locale de thread. Bogue n ° 3: lorsque vous renvoyez la valeur locale du thread, vous avez de la chance car ce sera la même chose que temp et aucun autre thread ne peut l'avoir changé, ce qui revient à utiliser une variable locale dans la tâche.

Dans votre deuxième exemple, vous faites la même erreur lors de l'initialisation. Mais alors vous continuez à compter deux fois les valeurs car la valeur locale du thread n'est pas réinitialisée au début de chaque tâche. Si deux tâches s'exécutent sur le même thread, la première peut retourner 1 + 2 + 3 et la seconde renvoyer 6 + 1 + 2 + 3.

+0

Il ne s'agit pas tant de savoir pourquoi le feriez-vous, mais plutôt d'une technique correcte. – Blair

+0

J'ai ajouté une explication plus détaillée sur la raison pour laquelle vos deux exemples sont «incorrects». –