Ist es in einem Java 7+ ForkJoinPool möglich, eine Aufgabe und alle Teilaufgaben abzubrechen?

8

Mein Programm sucht nach einer Lösung (einer beliebigen Lösung) für ein Problem durch einen Divide-and-Conquer-Ansatz, implementiert mit Rekursion und RecursiveTasks 's: Ich verzweifle eine Aufgabe für den ersten Zweig der Division und rekurriere dann in der zweite Zweig: wenn der zweite Zweig eine Lösung gefunden hat, dann annulliere ich den ersten Zweig, sonst warte ich auf sein Ergebnis.

Das ist vielleicht nicht optimal. Ein Ansatz wäre, dass eine der gestarteten Aufgaben eine Ausnahme auslöst, wenn eine Lösung gefunden wird. Aber wie würde ich dann alle gestarteten Aufgaben abbrechen? Werden durch Abbrechen einer Aufgabe auch alle Teilaufgaben abgebrochen?

    
David Monniaux 26.05.2014, 11:26
quelle

2 Antworten

2

Das Framework kann eine Aufgabe aus demselben Grund nicht abbrechen, aus dem Sie einen Thread nicht abbrechen können. Weitere Informationen finden Sie in der Dokumentation zu Thread.stop (). Welche Schlösser könnte die Aufgabe halten? Mit welchen externen Ressourcen könnte es verbunden sein? Alle gleichen Thread.stop () - Gründe gelten auch für Tasks (Tasks, die unter Threads ausgeführt werden.) Sie müssen die Task anweisen, genau so zu stoppen, wie Sie einem Thread sagen, dass er aufhören soll.

Ich verwalte ein anderes fork / join-Projekt, das die Scatter-Gather-Technik verwendet. Die Art, wie ich einen Abbruch oder einen Kurzschluss mache, besteht darin, dass jede Aufgabe, die ich erstelle, ein Objekt (PassObject) mit einem

übergeben wird %Vor%

und eine Methode zum Beenden der Aufgabe

%Vor%

Jede Aufgabe überprüft in regelmäßigen Abständen die stop_now und wenn sie wahr ist, wird die Aufgabe ordnungsgemäß beendet.

Unglücklicherweise muss der stop_now flüchtig sein, da ein anderer Thread ihn setzen wird. Dies kann erhebliche Mehrkosten verursachen, wenn Sie es häufig überprüfen.

Wie man dieses Feld in einer anderen Aufgabe einstellt, wird ein wenig schwierig. Jede Aufgabe, die ich erstelle, enthält auch einen Verweis auf das Array von Referenzen auf jede andere Aufgabe

%Vor%

Sobald die Liste gebildet ist, forkiere ich jedes Objekt in passList. Jedes PassObject enthält eine Referenz auf das Array passList, die einen Verweis auf jedes Objekt enthält, das an jede Task übergeben wird. Daher kennt jede Aufgabe jede andere Aufgabe und wenn eine Aufgabe die anderen abbrechen möchte, ruft sie einfach die Methode cancelOthers mit einem Verweis auf die PassList auf.

%Vor%

Wenn Sie Java8 verwenden, können Sie eine Scatter-Gather-Methode mit der Klasse CountedCompler anstelle der RecusiveTask durchführen. Für Java7 oder wenn Sie immer noch RecursiveTask verwenden möchten, muss die erste Task in der Rekursion ein AtomicBoolean-Feld erstellen (AtomicBoolean stop_now = new AtomicBoolean (false);) und einen Verweis auf dieses Feld in jeder neu erstellten RecursiveTask einfügen. Bei der Rekursion wissen Sie nicht, wie viele Aufgabenstufen Sie am Anfang benötigen. Auch hier müssen Sie in Ihrem Code regelmäßig nach einem "Wahr" im Booleschen Wert suchen. Wenn dies der Fall ist, beenden Sie die Aufgabe ordnungsgemäß.

Das obige ist nur ein Hinweis darauf, wie Sie einen Abbruch vornehmen können. Jede Anwendung ist anders. Was ich tue funktioniert für meine Anwendung - aber die Logik ist die gleiche. Sie benötigen etwas, das in jeder Aufgabe, die eine Aufgabe festlegen kann und die jede andere Aufgabe sehen kann, üblich ist.

Ich würde mehr Code hinzufügen, aber der Code fügt nur eine Zeile nach der anderen ein und ist nicht praktisch.

    
edharned 31.05.2014 18:59
quelle
2

Sie können den einfachen Ansatz mit Task-Manager verwenden. Zum Beispiel:

%Vor%

}

Und die Aufgabe:

%Vor%     
Vladimir Kishlaly 03.06.2014 18:36
quelle