3 votes

Redémarrage des fils normaux

Disons que je veux valider un million de chaînes de caractères et que chaque validation prend quelques secondes.

Mon approche :

J'ai un tableau de fils déclaré comme ceci :

Thread[] workers = new Thread[50];

Je n'ai pas toutes les chaînes de caractères dans un tableau, elles sont obtenues par des calculs, puis je ne les ai pas toutes lorsque je lance le processus, mais j'ai une méthode qui renvoie la suivante :

public string next()
{
  //my code
}

J'ai été capable d'exécuter les 50 fils comme ça :

for (int x = 0; x < 50; x++)
{
workers[x] = new Thread(new ParameterizedThreadStart(myMethod));
workers[x].Start(next());
}

Ce qui démarre rapidement les 50 threads "en même temps" et ensuite mon log (alimenté par myMethod) reçoit 50 réponses presque en même temps (1~1.5 seconde)

Comment puis-je faire en sorte que chaque thread qui vient de s'achever s'exécute à nouveau avec la chaîne suivante en tenant compte du fait que la classe Thread n'expose pas d'événement ou quelque chose de similaire ?

Note : J'ai fait quelques tests de performance, et je préfère utiliser les Threads réguliers plutôt que les BackgroundWorkers.

Utilisation de C# dans .net 3.5.

5voto

Reed Copsey Points 315315

On dirait que vous devriez utiliser le ThreadPool. Vous pourriez alors simplement faire :

while(MoreWorkIsAvailable)
{
    string nextString = next();
    ThreadPool.QueueUserWorkItem(new WaitCallback(myMethod), nextString);
}

Le pool de threads vous permettrait même de fixer un plafond au nombre maximum de threads à autoriser à fonctionner en même temps via SetMaxThreads .

2voto

Albin Sunnanbo Points 30722

Vous ne pouvez pas obtenir un événement par le système d'enfilage. Vous pouvez attendre un seul thread avec Thread.Join mais vous ne pouvez pas attendre n'importe quel fil et obtenir le fil qui se termine en premier. La meilleure approche consiste à placer une boucle while dans chaque thread qui interroge une file d'attente d'éléments de travail jusqu'à ce que la file soit vide.

1voto

Kendrick Points 3051

Vous pouvez utiliser votre méthode next() de la même manière qu'ADO.NET ou qu'une énumération. Continuez à renvoyer des valeurs jusqu'à ce que vous ayez terminé, puis renvoyez null. Demandez à vos threads de consommer la méthode dans une boucle while jusqu'à ce que la méthode renvoie null, puis quittez.

Pour clarifier, il y a un certain travail de fond que vous devrez faire. Vous devrez rendre votre méthode next() thread-safe afin de toujours renvoyer la valeur suivante sans doublons. Vous devrez également transmettre la référence à l'objet plutôt que la sortie de la méthode next(). La partie thread-safe est la seule chose vraiment compliquée à ce sujet, et cela signifie simplement que vous devez verrouiller la partie de votre méthode next() qui :

  • Détermine la prochaine valeur de chaîne à utiliser
  • et met à jour l'état de tout objet

Une fois que l'état est stable, vous pouvez libérer le verrou et le prochain thread peut obtenir sa chaîne pour travailler.

Edit : C'est peut-être encore la voie à suivre, bien que j'aime l'approche ThreadPool pour la simplicité. Dans ce cas, le code serait quelque chose comme :

YourStringGenerator generator;
//instatiate generator
for (int x = 0; x < 50; x++) 
{ 
    workers[x] = new Thread(new ParameterizedThreadStart(myMethod)); 
    workers[x].Start(generator); 
}

entonces

myMethod(YourStringGenerator generator)
{
    String compare;
    while((compare=generator.next())!=null)
    {
        //do comparison, etc.
    }
    return;
}

next() ressemblerait à quelque chose comme

String next()
{
    lock(this.index)  //see msdn for info.  Link below.
    {
        //determine next string
        //update index
    }
    //generate or get next string from list and return it
    //or if empty, return null
}

voir msdn pour info

1voto

uosɐſ Points 4466

Ajoutez à votre fil de discussion une méthode permettant de ne pas traiter uniquement une donnée mais la "prochaine non réclamée".

Vous voudrez avoir une certaine synchronisation autour du MoveNext d'un énumérateur, et récupérer une copie de la référence à Current. Deux threads ne pourront pas faire avancer l'énumérateur et saisir l'élément en même temps. Ensuite, une fois que vous avez votre référence, libérez le verrou de synchronisation et faites votre validation.

Vous pouvez également vous intéresser à l'extension parallèle Px de Microsoft pour tirer parti de plusieurs processeurs (cœurs ?). Je ne l'ai pas utilisé mais si votre validation est pure et algorithmique (plutôt que vérifiée par rapport à une base de données), l'implication de plusieurs processeurs est le seul moyen de battre le modèle monofil.

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