Es gibt eine große Menge an Aufgaben. Jede Aufgabe gehört zu einer einzelnen Gruppe. Die Anforderung besteht darin, dass jede Gruppe von Aufgaben seriell ausgeführt werden sollte, genauso wie sie in einem einzelnen Thread ausgeführt werden, und der Durchsatz sollte in einer Multicore- (oder Multi-CPU-) Umgebung maximiert werden. Hinweis: Es gibt auch eine große Anzahl von Gruppen, die proportional zur Anzahl der Aufgaben ist.
Die naive Lösung verwendet ThreadPoolExecutor und synchronisiert (oder sperrt). Threads würden sich jedoch gegenseitig blockieren und der Durchsatz wird nicht maximiert.
Irgendeine bessere Idee? Oder gibt es eine Drittanbieter-Bibliothek, die die Anforderung erfüllt?
Ein einfacher Ansatz wäre es, alle Gruppenaufgaben in eine Superaufgabe zu "verketten", wodurch die Teilaufgaben seriell ausgeführt werden. Dies führt jedoch wahrscheinlich zu einer Verzögerung in anderen Gruppen, die erst gestartet werden, wenn eine andere Gruppe vollständig beendet ist und im Thread-Pool Platz findet.
Alternativ können Sie die Aufgaben einer Gruppe verketten. Der folgende Code veranschaulicht es:
%Vor%Der Vorteil ist, dass keine zusätzliche Ressource (Thread / Queue) verwendet wird und dass die Granularität von Tasks besser ist als die im naiven Ansatz. Der Nachteil ist, dass alle Gruppenaufgaben im Voraus bekannt sein sollten .
- bearbeiten -
Um diese Lösung generisch und vollständig zu machen, möchten Sie vielleicht die Fehlerbehandlung (dh ob eine Kette fortgesetzt wird, selbst wenn ein Fehler auftritt) entscheiden, und es wäre auch eine gute Idee, ExecutorService zu implementieren und alle Aufrufe an die zugrunde liegenden Executor.
Ich würde vorschlagen, Task-Queues zu verwenden:
Eine schnelle Google-Suche legt nahe, dass die Java-API selbst keine Task- / Thread-Warteschlangen hat. Es gibt jedoch viele Tutorials zum Codieren eines. Jeder kann sich gute Tutorien / Implementierungen nennen, wenn Sie einige kennen:
Ich stimme hauptsächlich Daves Antwort zu, aber wenn Sie die CPU-Zeit über alle "Gruppen" hinweg teilen müssen, dh alle Aufgabengruppen sollten parallel fortschreiten, könnten Sie diese Art von Konstrukt nützlich finden (Entfernen als "Sperre") hat in meinem Fall gut funktioniert, obwohl ich mir vorstelle, dass es mehr Speicher verbraucht):
%Vor%und
%Vor% Sie können dann die optimale Anzahl von Threads verwenden, um die Aufgabe DoWork
auszuführen. Es ist eine Art Round-Robin-Lastausgleich.
Sie können sogar etwas anspruchsvolleres tun, indem Sie dies anstelle einer einfachen Warteschlange in TaskAllocator
verwenden (Aufgabengruppen mit mehr verbleibenden Aufgaben werden in der Regel ausgeführt)
wobei SophisticatedComparator
Ich hatte ein ähnliches Problem wie Sie, und ich habe ein ExecutorCompletionService
verwendet, das mit einem Executor
arbeitet, um eine Sammlung von Aufgaben zu vervollständigen.
Hier ist ein Auszug aus java.util.concurrent API, seit Java7:
%Vor%Angenommen, Sie haben eine Reihe von Solvern für ein bestimmtes Problem, die jeweils einen Wert vom Typ Ergebnis zurückgeben und sie gleichzeitig ausführen möchten. Dabei werden die Ergebnisse jedes einzelnen, die in einer Methode einen Nicht-Null-Wert zurückgeben, verarbeitet Verwenden (Ergebnis r). Sie könnten dies wie folgt schreiben:
In Ihrem Szenario ist also jede Aufgabe eine einzige Callable<Result>
und Aufgaben werden in einer Collection<Callable<Result>>
gruppiert.
Referenz: Ссылка
Tags und Links scala java akka actor threadpool