53 votes

Faire apparaître plusieurs threads pour le travail, puis attendre que tout soit terminé

tout simplement des conseils sur les "meilleures pratiques" concernant le multi-threading tâches.

comme un exemple, nous avons une application en C# qui, au démarrage, lit les données à partir de plusieurs "type" de la table dans notre base de données et stocke les informations dans une collection qui nous passe autour de l'application. cela nous empêche de frapper la base de données à chaque fois que cette information est nécessaire.

au moment de l'application est de la lecture des données à partir de 10 tables de façon synchrone. je voudrais vraiment avoir l'application de lecture de chaque table dans un thread différent de tous les exécutant en parallèle. l'application s'attendre à tous les fils avant de passer à la mise en service de l'application.

j'ai regardé dans BackGroundWorker, mais tout simplement des conseils sur la réalisation de la ci-dessus.

  1. La méthode logique afin d'accélérer le temps de démarrage de notre application
  2. Comment pouvons-nous mieux gérer tous les threads en gardant à l'esprit que chaque thread de travail est indépendant l'un de l'autre, nous avons juste besoin d'attendre que tous les threads se termine avant de continuer.

je m'attends à des réponses

91voto

Reed Copsey Points 315315

Ma préférence pour cela est de gérer cela via un seul WaitHandle et d'utiliser Interlocked pour éviter le verrouillage sur un compteur:

 class Program
{
    static void Main(string[] args)
    {
        int numThreads = 10;
        ManualResetEvent resetEvent = new ManualResetEvent(false);
        int toProcess = numThreads;

        // Start workers.
        for (int i = 0; i < numThreads; i++)
        {
            new Thread(delegate()
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                // If we're the last thread, signal
                if (Interlocked.Decrement(ref toProcess) == 0)
                    resetEvent.Set();
            }).Start();
        }

        // Wait for workers.
        resetEvent.WaitOne();
        Console.WriteLine("Finished.");
    }
}
 

Cela fonctionne bien et s’adapte à n’importe quel nombre de processus de traitement, sans introduire de verrouillage.

28voto

Jack Leitch Points 464

J'aime la solution de @ Reed. Un autre moyen de réaliser la même chose dans .NET 4.0 consiste à utiliser un événement CountdownEvent .

 class Program
{
    static void Main(string[] args)
    {
        var numThreads = 10;
        var countdownEvent = new CountdownEvent(numThreads);

        // Start workers.
        for (var i = 0; i < numThreads; i++)
        {
            new Thread(delegate()
            {
                Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
                // Signal the CountdownEvent.
                countdownEvent.Signal();
            }).Start();
        }

        // Wait for workers.
        countdownEvent.Wait();
        Console.WriteLine("Finished.");
    }
}
 

9voto

Benjamin Ortuzar Points 3585

Si vous avez plus de 64 poignées d’attente pour un thread STA, comme le dit Mark. vous pouvez créer une liste avec vos discussions et attendre que tout soit terminé dans une seconde boucle.

 //check that all threads have completed.
foreach (Thread thread in threadList)
{
     thread.Join();

}  
 

7voto

Mark Byers Points 318575

Si vous n'êtes pas sur .NET 4.0, puis vous pouvez utiliser une Liste de<ManualResetEvent>, une pour chaque thread et Attendre pour eux d'être Ensemble. Attendre sur plusieurs threads, vous pourriez envisager d'utiliser des WaitAll mais attention à la limite de 64 attendre poignées. Si vous avez besoin de plus que cela, vous pouvez simplement en boucle sur eux et d'attendre de chacun d'eux individuellement.

Si vous voulez un démarrage plus rapide exprience, vous n'avez probablement pas besoin d'attendre que toutes les données devant être lues au cours du démarrage. Juste l'affichage de l'interface graphique, et toute information manquante peut être affichée en grisé avec une sorte de "mise à Jour..." icône ou similaire. Lorsque l'information arrive, juste le feu à un événement de mise à jour de l'interface graphique. Il pourrait y avoir de nombreuses opérations que l'utilisateur peut commencer à effectuer avant même de toutes les données de toutes les tables, est lu.

6voto

Benjamin Ortuzar Points 3585

Si vous vous sentez aventureux, vous pouvez utiliser C # 4.0 et la bibliothèque de tâches parallèle:

 Parallel.ForEach(jobList, curJob => {
  curJob.Process()
});
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X