2017-10-15 9 views
2

ne peut pas comprendre un exemple dans un livre d'apress parler d'un cas mal utilisé de threadlocal avec construction de tâche dans TPL.pourquoi C# ThreadLocal ne fonctionne pas comme prévu avec Task dans TPL?

Pourquoi n'est-il pas devenu 10000 en nombre comme résultats attendus?

Quelqu'un pourrait-il donner une explication plus détaillée sur le déroulement du programme du programme ci-dessous pour lequel la ligne s'exécute instantanément et certaines lignes sont asynchrones dans le temps? la séquence et l'ordre d'exécution?

using System; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Listing_05 { 

class BankAccount { 
    public int Balance { 
     get; 
     set; 
    } 
} 

class Listing_05 { 

    static void Main(string[] args) { 

     // create the bank account instance 
     BankAccount account = new BankAccount(); 

     // create an array of tasks 
     Task<int>[] tasks = new Task<int>[10]; 

     // create the thread local storage 
     ThreadLocal<int> tls = new ThreadLocal<int>(() => { 
      Console.WriteLine("Value factory called for value: {0}", 
       account.Balance); 
      return account.Balance; 
     }); 

     for (int i = 0; i < 10; i++) { 
      // create a new task 
      tasks[i] = new Task<int>(() => { 

       // enter a loop for 1000 balance updates 
       for (int j = 0; j < 1000; j++) { 
        // update the TLS balance 
        tls.Value++; 
       } 

       // return the updated balance 
       return tls.Value; 

      }); 

      // start the new task 
      tasks[i].Start(); 
     } 

     // get the result from each task and add it to 
     // the balance 
     for (int i = 0; i < 10; i++) { 
      //added by myself to see any hints but still cannot have insights 
      Console.WriteLine("task {0} results {1}", i, tasks[i].Result); 
      //end of my editing 

      account.Balance += tasks[i].Result; 
     } 

     // write out the counter value 
     Console.WriteLine("Expected value {0}, Balance: {1}", 
      10000, account.Balance); 

     // wait for input before exiting 
     Console.WriteLine("Press enter to finish"); 
     Console.ReadLine(); 
    } 
} 

}

résultats dans un ordinateur en utilisant 8 cœurs cpu I7 sont 8 fils. Exécuter Plusieurs fois et ci-dessous sont 2 sur plusieurs exécutions.

1st execute

2nd execute

Ne pas comprendre comment les programmes fonctionnent et se comportent de cette façon

+0

Voir https://particular.net/blog/the-dangers-of-threadlocal –

+0

Oui, je viens de faire google sur le lien ci-dessus avant de poser des questions ci-dessus, mais peut-être que je suis un novice sur ce sujet de discussion, donc je peux difficilement comprendre la situation pourquoi le programme se comporte comme ça. Jusqu'à présent, ma compréhension est ThreadLocal est des données locales à thread seulement. La tâche est déclarative et vous décrivez la tâche à effectuer par un thread de travail inconnu. Il est inconnu que les données initialisées locales de thread vont planter en raison de certaines tâches sur 10 réutiliser les mêmes données de thread en cours de modification dans certaines des 10 tâches? quelqu'un pourrait décrire comment l'exécution de cet exemple est ... une ligne devrait être reportée à courir? – Cuda

+0

@Cuda, vous avez deux 'compte.Balance' dans votre usine de valeur. Les deux ont le droit de retourner des résultats différents. – PetSerAl

Répondre

2

Les tâches offrent un mécanisme permettant d'exécuter du code en même temps. Cela ne signifie pas qu'ils fonctionneront nécessairement sur des threads séparés ou même si plusieurs threads sont utilisés pour qu'ils ne soient pas réutilisés. N'essayez pas d'utiliser le stockage local de thread avec Tâches du tout. Les options de stockage alternatives doivent utiliser une fermeture dans la fonction lambda de la tâche ou créer une classe et placer des données sur cette classe et utiliser une méthode de cette classe en tant qu'appelée de la tâche. Personnellement, je pense que c'est beaucoup plus propre de toute façon.

Hans Passant a également mentionné AsyncLocal dans les commentaires qui mériteraient d'être recherchés (je ne l'ai pas utilisé moi-même, donc je ne peux pas faire de commentaire).

+0

Donc vous voulez dire qu'il peut s'agir de 1 thread pour faire Tâches simultanément ou de plusieurs threads pour faire des Tâches simultanément, pas de garantie sur la réutilisation du thread, donc n'utilisez pas de stockage local thread qui n'est local que pour un seul thread? Que devrait-on utiliser pour les tâches de stockage de données? – Cuda