2009-08-04 6 views
5

Je cherche une classe où je peux remplacer une méthode pour faire le travail, et renvoyer les résultats comme un itérateur. Quelque chose comme ceci:Java itérateur de travail parallèle?

ParallelWorkIterator<Result> itr = new ParallelWorkIterator<Result>(trials,threads) { 

    public Result work() { 
    //do work here for a single trial... 
    return answer; 
    } 

}; 
while (itr.hasNext()) { 
    Result result = itr.next(); 
    //process result... 
} 

Cela va principalement être utilisé pour des choses comme des simulations de Monte Carlo, mais je ne veux pas avoir à faire face à la mise en place des pools de threads et la gestion des fils qui reviennent à chaque fois. J'ai roulé ma propre classe que j'espère que accomplit ceci, mais je ne suis pas assez confiant dedans et ai pensé vérifier si quelque chose comme ceci existait déjà. Editer: Pour être clair, je veux qu'il continue à fonctionner en arrière-plan et que les résultats de mise en file d'attente après que chaque méthode de travail revient jusqu'à ce que tous les essais ont été achevés. Ainsi, la méthode suivante peut attendre de retourner jusqu'à ce qu'il y ait un résultat dans la file d'attente.

Répondre

12

Jetez un oeil à la ExecutorCompletionService. Il fait tout ce que tu veux. L'avantage d'utiliser un CompletionService est qu'il renvoie toujours le premier résultat terminé. Cela garantit que vous n'attendez pas la fin des tâches et que les tâches inachevées s'exécutent en arrière-plan.

+0

Merci, on dirait qu'il fait tout ce que je veux. Je souhaite juste que java n'était pas si prolixe. – job

+3

verbeux et non équivoque sont la moitié d'une épée à double tranchant. –

+0

Ce que j'ai fait pour gérer la verbosité est d'écrire une classe wrapper qui étend ExecutorCompletionService, et conserve une liste des futurs soumis. Un booléen public hasRemaining() {return 0 Tim

2

Je recommande de regarder Java Executors.

Vous soumettez un certain nombre de tâches et récupérez un objet Future pour chacune d'entre elles. Votre travail est traité en arrière-plan et vous parcourez les objets du futur (comme vous le faites ci-dessus). Chaque Future renvoie un résultat dès qu'il est disponible (en appelant get() - cela bloque jusqu'à ce que le résultat ait été généré dans un thread séparé)

1

La chose la plus proche que je puisse penser est d'utiliser un CompletionService pour accumuler des résultats à mesure qu'ils se terminent.

Exemple simple:

ExecutorService executor = Executors.newSingleThreadExecutor(); // Create vanilla executor service. 
CompletionService<Result> completionService = new ExecutorCompletionService<Result>(executor); // Completion service wraps executor and is notified of results as they complete. 
Callable<Result> callable = new MyCallable(); 

executor.submit(callable); // Do not store handle to Future here but rather obtain from CompletionService when we *know* the result is complete. 

Future<Result> fut = completionService.take(); // Will block until a completed result is available. 
Result result = fut.get(); // Will not block as we know this future represents a completed result. 

Je ne recommanderais pas envelopper tout cela derrière une interface Iterator comme méthode Futureget() peut lancer deux exceptions vérifiées possibles: ExecutionException et InterruptedException, et vous auriez besoin donc d'attraper et soit avaler ceux-ci ou les repasser comme RuntimeException s, dont aucun n'est une très bonne chose à faire. En outre, vos méthodes IteratorhasNext() ou next() auraient potentiellement besoin de bloquer s'il y avait une tâche en cours, ce qui pourrait être considéré comme contre-intuitif pour les clients utilisant un Iterator. Au lieu de cela, j'implémenterais ma propre interface plus descriptive; par exemple.

public interface BlockingResultSet { 
    /** 
    * Returns next result when it is ready, blocking is required. 
    * Returns null if no more results are available. 
    */ 
    Result take() throws InterruptedException, ExecutionException; 
} 

(méthodes appelées take() représentent généralement un appel de blocage dans le package java.util.concurrent).