Je me demande si c'est la meilleure façon de le faire. J'ai environ 500 threads qui exécutent indéfiniment, mais Thread.sleep pendant une minute quand un cycle de fini traitement.
class aThread extends Thread { public void run(){ while(true){ Thread.sleep(ONE_MINUTE); //Lots of computation every minute } } }
11 Réponses :
Si vos threads ne se terminent pas, c'est le défaut du code dans le fil, pas le pool de threads. Pour une aide plus détaillée, vous devrez publier le code exécuté. P>
Aussi, pourquoi mettez-vous chaque fil au sommeil lorsqu'il est fait? Ne serait-il pas mieux que de le laisser complète? p>
En outre, je pense que vous prenez une mauvaise utilisation de la piscine de fil en ayant un certain nombre de threads égaux au nombre de tâches que vous souhaitez exécuter. Le point d'un bassin de fil est de mettre une contrainte sur le nombre de ressources utilisées; Cette approche n'est pas meilleure que d'utiliser une piscine de fil du tout. P>
Enfin, vous n'avez pas besoin de passer des instances de thread code> à votre
exécutantservice code>, juste des instances de
exécubles code>.
exécuteur code> maintient son propre pool de threads qui boucle indéfiniment, tirant de l'édification d'une file d'attente interne (le travail étant le
exécutable code> Soumettez-vous). P>
Correct. L'exécuteur n'a aucune idée d'un sommeil runnable. Jusqu'à ce que l'exécuteur exécutable soit terminée, l'exécuteur le pense qu'il fonctionne.
Je ne suis pas sûr que votre code soit sémantiquement correct dans la manière dont il utilise une piscine de fil. ExecutionService crée et gère les threads en interne, un client doit simplement fournir une instance de méthode exécutable, dont la méthode d'exécution () sera exécutée dans le contexte de l'un des filets poolés. Vous pouvez vérifier Mon exemple . Notez également que chaque fil d'exécution prend environ 10 Mo de mémoire système pour la pile et sous Linux, la cartographie des fils Java-Native est de 1 à 1. p>
Au lieu de mettre une bande de roulement pour dormir, vous devez le laisser retourner et utiliser un threadpoolexecutor pour exécuter le travail affiché chaque minute à votre file d'attente de travail. P>
Vous avez besoin d'un sémaphore.
Semaphore sem = new Semaphore(MAX_AVAILABLE, true);
L'OP n'a rien mené à propos de la synchronisation. Ceci est complètement hors sujet.
L'OP a demandé à un moyen de s'assurer que seul un nombre fixe de thread est "actif" à un moment donné, ce qui est un problème de synchronisation. Peut-être que ma solution n'est pas optimale (j'aime la solution acceptée) à coup sûr de ne pas éteindre la succursale car elle résout le problème.
8 threads est le max que votre système peut gérer, plus et que vous vous ralentisiez avec une commutation de contexte. p>
Regardez cet article http://www.informit.com /Articles/article.aspx?p=1339471&eqnum=4 Cela vous donnera un aperçu de la façon de le faire. P>
Cela assume le traitement lié à la CPU. Il n'est pas correct si les threads sont liés I / O.
@Willie Wheeler - Dans les commentaires de la question, il dit qu'il effectue des calculs. Il est probablement sûr de supposer qu'il est lié à la CPU. Avez-vous lu ou juste ding?
Pour répondre à votre question, quel type de piscine de fil? p>
J'ai posté mes commentaires mais cela devrait vraiment répondre à votre problème. Vous avez un calcul pouvant prendre 2 secondes à compléter. Vous avez de nombreuses tâches (500) que vous souhaitez être complété le plus rapidement possible. Le débit possible possible que vous pouvez réaliser, en supposant qu'il n'y ait pas d'io et ni de trafic réseau, est avec Si vous augmentez votre nombre à 500 threads, chaque tâche s'exécutera sur son propre thread, mais le système d'exploitation planifiera un fil de chaque fois pour donner à un autre fil. THITS 125 Contexte change à tout point donné. Chaque commutateur de contexte augmentera la quantité de temps pour chaque tâche à exécuter. p>
La grande image ici est que l'ajout de plus de threads ne correspond pas à un débit plus important lorsque vous êtes bien sur le nombre de processeurs. p>
Edit: une mise à jour rapide. Vous n'avez pas besoin de dormir ici. Lorsque vous exécutez les 500 tâches avec 8 processeurs, chaque tâche terminera dans les 2 secondes, la finition et le fil qu'il fonctionnait sur une tâche suivante et remplissez celui-ci. p> runtime.getruntime (). Dispocapesseurs () code> Nombre de threads. P>
Pourquoi pas utilisé un planchedexecutetorservice code> à Planifiez chaque tâche à exécuter une fois par minute, au lieu de laisser tous ces threads oisif pour une minute complète?
ScheduledExecutorService workers =
Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
for (Runnable task : list) {
workers.scheduleWithFixedDelay(task, 0, 1, TimeUnit.MINUTES);
}
Clairement, il ne devrait pas utiliser de threads, il devrait simplement implémenter runnable code>, et chaque
exécution () code> doit terminer après un seul calcul.
Ce serait la meilleure solution que l'OP recherche si chaque exécutable n'est pas dans une boucle éternelle et quitte la méthode de course après la fin d'une seule course.
Vous pouvez certainement trouver une certaine amélioration du débit en réduisant le nombre de threads à ce que le système peut gérer de manière réaliste. Êtes-vous ouvert à changer un peu la conception du fil? Ça va désactiver le planificateur de mettre les sommeil dans une file d'attente au lieu d'avoir des centaines de fils endormis.
class RepeatingWorker implements Runnable { private ExecutorService executor; private Date lastRan; //constructor takes your executor @Override public void run() { try { if (now > lastRan + ONE_MINUTE) { //do job lastRan = now; } else { return; } finally { executor.submit(this); } } }
J'ai besoin d'un threads séparé pour chaque tâche en cours d'exécution, ce qui modifie donc l'architecture n'est pas une option. p>
si em> qui est vrai (par exemple, appelez une fonction de blocage externe), créez-les, puis créez des threads distincts pour eux et commencez-les. Vous ne pouvez pas créer de piscine de thread avec un nombre limité de fils, car une fonction de blocage dans l'un des threads empêchera toute autre édition de la mise en place, et ne gagnez pas grand chose à créer une piscine de fil avec un fil par tâche.
J'ai essayé de faire ma taille de threadpool égale à Runtime.getruntime (). À la disposition des propulseurs () qui ont tenté d'exécuter les 500 threads, mais seulement 8 (4xhyperthreading) d'entre eux s'exécutent. p> blockQuote>
Lorsque vous passez les objets de thread, vous créez pour filer la piscine, il ne voit que des éléments qu'elles implémentent
runnable code>. Par conséquent, il exécutera chaque
exécutable code> à l'achèvement. Toute boucle qui arrête la méthode code> (code> La méthode de retour ne permettra pas la prochaine tâche en cours d'exécution; par exemple: p>
xxx pré> imprime: p>
Task {0} iteration {1} thread {Thread[pool-1-thread-1,5,main]}. Task {1} iteration {1} thread {Thread[pool-1-thread-2,5,main]}. Task {0} iteration {2} thread {Thread[pool-1-thread-1,5,main]}. Task {1} iteration {2} thread {Thread[pool-1-thread-2,5,main]}. Task {0} iteration {3} thread {Thread[pool-1-thread-1,5,main]}. Task {1} iteration {3} thread {Thread[pool-1-thread-2,5,main]}. Task {0} iteration {4} thread {Thread[pool-1-thread-1,5,main]}. Task {2} iteration {1} thread {Thread[pool-1-thread-1,5,main]}. Task {1} iteration {4} thread {Thread[pool-1-thread-2,5,main]}. Task {3} iteration {1} thread {Thread[pool-1-thread-2,5,main]}. Task {2} iteration {2} thread {Thread[pool-1-thread-1,5,main]}. Task {3} iteration {2} thread {Thread[pool-1-thread-2,5,main]}. Task {2} iteration {3} thread {Thread[pool-1-thread-1,5,main]}. Task {3} iteration {3} thread {Thread[pool-1-thread-2,5,main]}. Task {2} iteration {4} thread {Thread[pool-1-thread-1,5,main]}. ...
- si vous voulez que toutes les tâches exécutions soient exécutées en même temps, tout attendre une minute, puis tous courir à la fois, ou si les tâches ne sont pas synchronisées les unes avec les autres li>
- si vous vouliez vraiment que chaque tâche soit exécutée à un intervalle d'une minute li>
- si vos tâches sont potentiellement bloquantes ou non, et nécessitent donc vraiment des threads distincts li>
- quel comportement est attendu si une tâche bloque plus longtemps que la fenêtre attendue pour exécuter li>
- quel comportement est attendu si une tâche bloque plus longtemps que la fréquence de répétition (blocs pendant plus d'une minute) li> ul>
Selon les réponses à celles-ci, une combinaison de planifiedexecuterservice, de sémaphores ou de mutiles peut être utilisée pour coordonner les tâches. Le cas le plus simple est les tâches non bloquantes et non synchrones, auquel cas utilisez une planchedExecutetorservice directement pour exécuter vos runnables une fois par minute. P> blockQquote>
Comme déjà dit, faites attention à l'utilisation du rendement () introduisant une «attente occupée» et doit être évitée.
Je pensais que tu avais dit que ce n'était pas une "attente occupée", alors c'est quoi?
Pouvez-vous réécrire votre projet d'utiliser un cadre de concurrence basé sur agent, comme akka ? P>
Cela devrait faire ce que vous désirez, mais pas ce que vous avez demandé :-) Vous devez sortir le fichier thread.sleep () code>
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledRunnable
{
public static void main(final String[] args)
{
final int numTasks = 10;
final ScheduledExecutorService ses = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors());
for (int i = 0; i < numTasks; i++)
{
ses.scheduleAtFixedRate(new MyRunnable(i), 0, 10, TimeUnit.SECONDS);
}
}
private static class MyRunnable implements Runnable
{
private int id;
private int numRuns;
private MyRunnable(final int id)
{
this.id = id;
this.numRuns = 0;
}
@Override
public void run()
{
this.numRuns += 1;
System.out.format("%d - %d\n", this.id, this.numRuns);
}
}
}
Y a-t-il une raison particulière pour laquelle vous ne pouvez pas les faire simultanément séquentielle? C'est 8 courir simultanément et collecter des résultats et al quand ils sont terminés. La question est que cela prendra toujours le même temps si vous le faites avec 500 threads ou si vous le faites avec 8 threads.
Combien de temps faut-il un calcul en soi? Combien de temps faut-il un calcul s'il est exécuté dans les 500 threads?
Ce n'est pas clair pour moi ce que tu veux faire. Pourquoi n'essayez-vous pas simplement de courir tous vos discussions? Quelque chose comme: pour (int i ....) {((thread) coreappvector.Elementat (i)). Début (); }
Le calcul prend environ 2 secondes, mais avec 500 threads, il y a une tonne de blocage, ce qui signifie que certains threads peuvent prendre jusqu'à 2 minutes pour effectuer leur travail. C'est un cauchemar en ce moment et je cherche à dire seulement 8 de travailler à un moment donné et une fois qu'ils ont terminé leurs 2 secondes, laissez-vous suivre un autre threads et ainsi de suite
Andrea: Courir 500 threads à la fois est ce que je fais maintenant, mais il semble que cela semble se battre pour des ressources système (depuis que je n'ai que 4 cœurs physiques). Certains threads peuvent être bloqués si bloqués qu'ils prennent jusqu'à deux minutes pour finir..Perhaps, il s'agit simplement d'une limitation de la quantité de travail nécessaire pour être effectuée et du pouvoir de traitement de le faire.
Plus précisément, pourquoi appelez-vous sommeil ()?
La réalité est que cela prendra une durée plus longue avec 500 threads puis avec 8 threads. Avec seulement 8 processeurs distincts, il y aura une énorme quantité de commutation de contexte. Cela fera que chaque deuxième calcul soit beaucoup plus longtemps.
500 threads sont au moins 492 trop nombreux dans votre cas. Puisque vous utilisez HyperThreading, vous n'avez même pas 8 vrais processeurs. Je dirais utiliser 4 threads dans une configuration rond-robine et vous aurez probablement la meilleure performance.
Je me rends compte que je ne devrais utiliser que 4 threads, mais les threads doivent exécuter un bloc de code exactement à la minute, en quelque sorte comme sondage chaque minute si vous voulez y penser de cette façon. Ils dorment est de maintenir cet intervalle d'une minute. Je ne peux pas les avoir terminé, puis leur boucle interne n'exécutera pas ce code chaque minute ... ai-je raison de penser que, à moins que cette méthode de course () ne se termine jamais, aucun autre thread ne peut commencer par un threadpool de tailles 4 et 500 ?
@Submerged - Il existe d'autres moyens de maintenir l'intervalle d'une minute (d'ailleurs, vous n'avez pas d'intervalle d'une minute, vous avez une minute + intervalle de temps de calcul). Débarrassez-vous du sommeil et utilisez un mécanisme de planification légitime.
@Submereed. Si vous utilisez un service d'exécution, chaque exécutable qui fonctionne pour toujours ne terminera jamais (comme vous pouvez l'imaginer) et que la piscine de thread ne déléguera jamais la tâche suivante à un fil libre (car il n'y en a pas).
Ok, comme je pensais. Le problème est vraiment ça. Permettez-moi de vous donner une idée de ce que le programme fait pour le mettre en perspective. Chaque thread effectue une transformation génétique, essentiellement un algorithme d'apprentissage pour analyser les tendances. Si le fil se termine, cet apprentissage est également perdu. C'est la raison pour laquelle chaque thread ne peut jamais se terminer, mais plutôt dormir () dans l'espoir de se rendre certains de ses ressources ... Malheureusement, il semble que ce n'est pas possible car il ne se termine jamais.
@SUBMereedged Vous pouvez utiliser ce que Erickson a suggéré avec un planificateurExecutservice, maintenez cet état dans le fichier runnable et vous devriez pouvoir conserver les informations.
Mais est-ce absolument nécessaire qu'ils soient des objets enfilés? Vous pouvez les rendre courants et les laisser préserver cet état interne important, puis invoquer la course, selon le cas dans un certain nombre de threads gérables pour votre système. (qui peut être plus de 4 ou 8 si une partie de la tâche bloque sur le réseau / la base de données / quel que soit l'IO.)
Cela pourrait être ce que je cherche. Merci tout le monde! Je présenterai demain, car il est 17h ici et que vous sachiez comment j'ai fait. Super aide comme toujours !!
Juste parce qu'il n'y a que huit cœurs (logiques) ne signifie pas que les meilleures performances proviendront de huit threads. Si les threads sont liés à la CPU, huit seront plus proches de droite, mais si les threads sont liés à IO, il peut bien vouloir avoir du sens d'avoir beaucoup plus de threads. D'accord avec l'idée générale cependant que vous devez faire attention à garder le contexte changer de contexte sous contrôle.
@Fuzzy Lollipop Bien sûr, un état endommagé peut tenir l'état. Si vous avez une collection d'un type de classe qui implémente en cours d'exécution avec certains états et exécutez ces runnables, ces runnables conserveront l'état à chaque exécution.
Merci John, c'est ce que je voulais entendre
Pour que quiconque lisait ceci à l'avenir. J'ai mis en œuvre ma réponse acceptée et une fois que j'ai réellement mis en œuvre une finition () courante (), j'ai vu une augmentation de 50 à 75% de vitesse. Merci tout le monde