Java - effiziente Terminierungsstruktur?

8

Ich entschuldige mich für die Länge dieses Problems, aber ich hielt es für wichtig, genügend Details einzubeziehen, da ich nach einem geeigneten Ansatz für mein Problem suche, anstatt nach einem einfachen Code-Vorschlag!

Allgemeine Beschreibung:

Ich arbeite an einem Projekt, bei dem Aufgaben in einem relativen Wiederholungsintervall werden können.

Diese Intervalle beziehen sich auf eine interne Zeit, die als Ganzzahl dargestellt wird, die bei der Ausführung des Programms inkrementiert wird ( also nicht gleich der tatsächlichen Zeit ). Jedes Mal, wenn dies geschieht, wird der Zeitplan abgefragt, um nach Aufgaben zu suchen, die zu diesem Zeitpunkt ausgeführt werden sollen.

Wenn eine Aufgabe ausgeführt wird, sollte sie erneut geplant werden, um an einer Position relativ zu der aktuellen Zeit erneut ausgeführt zu werden (z. B. in 5 Zeitschritten). Diese relative Position wird einfach als Integer-Eigenschaft des Task-Objekts gespeichert.

Das Problem:

Ich habe Schwierigkeiten, darüber zu entscheiden, wie ich das strukturieren soll - zum Teil, weil es sich um eine etwas schwierige Suche nach Begriffen handelt.

Wie es aussieht, denke ich, dass jedes Mal, wenn der Timer inkrementiert wird, muss:

  1. Ausführen von Aufgaben an der Position '0' im Zeitplan
  2. Fügen Sie diese Aufgaben erneut dem Zeitplan an ihrer relativen Position hinzu (z. B. wird eine Aufgabe, die alle 5 Schritte wiederholt wird, an die Position 5 zurückgegeben)
  3. Für jede Gruppe von Aufgaben im Zeitplan wird die "Zeit bis zur Ausführung" um eins verringert (z. B. wird eine Aufgabe an Position 1 auf Position 0 verschoben)

Annahmen:

Es gibt ein paar Annahmen, die die möglichen Lösungen einschränken können, die ich verwenden kann:

  • Das Intervall muss relativ sein, keine bestimmte Zeit und ist als ganze Zahl von Schritten von der aktuellen Zeit
  • definiert
  • Diese Intervalle können einen beliebigen ganzzahligen Wert annehmen, z. sind nicht begrenzt .
  • Mehrere Aufgaben können für denselben Zeitschritt geplant werden, aber ihre Reihenfolge der Ausführung ist nicht wichtig
  • Die gesamte Ausführung sollte in einem einzigen Thread bleiben - Multi-Thread-Lösungen sind nicht aufgrund anderer Einschränkungen
  • geeignet

Die wichtigsten Fragen, die ich habe, sind:

Wie könnte ich diesen Zeitplan so gestalten, dass er effizient funktioniert? Welche Datentypen / Sammlungen können nützlich sein?

Gibt es eine andere Struktur / Vorgehensweise, die ich in Betracht ziehen sollte?

Ist es falsch, Terminierungs-Frameworks (z. B. Quartz) zu verwerfen, die eher in der "echten" Zeitdomäne als in der "nicht realen" Zeitdomäne funktionieren?

Vielen Dank für jede mögliche Hilfe. Bitte zögern Sie nicht für weitere Informationen zu kommentieren, falls erforderlich, werde ich wo immer nötig bearbeiten!

    
obfuscation 09.09.2011, 14:08
quelle

7 Antworten

1

Wie wäre es damit, verwendet es Ihre eigenen Ticks mit executeNextInterval ():

%Vor%

Vielleicht möchten Sie etwas Fehlerbehandlung hinzufügen, aber es sollte Ihre Arbeit machen.

Und hier sind einige UnitTests dafür:)

%Vor%     
flob 09.09.2011, 14:22
quelle
2

Nun, Quartz ist ziemlich mächtige Werkzeuge, aber es hat begrenzte Konfigurationsmöglichkeiten, wenn Sie also bestimmte Funktionen benötigen, sollten Sie wahrscheinlich Ihre eigene Lösung schreiben.

Es ist jedoch eine gute Idee, den Quartz Quellcode und die Datenstrukturen zu studieren, da sie erfolgreich viele Probleme gelöst haben, die Sie z. Synchronisation zwischen Prozessen auf Datenbankebene, Ausführung von verzögerten Aufgaben usw.

Ich habe einmal meinen eigenen Scheduler geschrieben, der an Aufgaben angepasst wurde, bei denen Quartz wahrscheinlich nicht einfach anzupassen wäre, aber sobald ich Quarz gelernt habe, habe ich verstanden, wie viel ich in meinen Lösungen verbessern konnte wurde in Quarz gemacht.

    
Danubian Sailor 09.09.2011 14:22
quelle
1

Eine kreisförmige verkettete Liste könnte die Datenstruktur sein, nach der Sie suchen. Anstatt Felder in jedem Aufgabenelement zu dekrementieren, erhöhen Sie einfach den Index des 'aktuellen' Feldes in der kreisförmigen Aufgabenliste. Eine Pseudocode-Struktur könnte etwa so aussehen:

%Vor%

Wenn Sie eine neue Aufgabe planen, fügen Sie sie einfach an der Position N vor dem aktuellen 'Tick'

hinzu     
mcfinnigan 09.09.2011 14:21
quelle
1

Hier sind ein paar Gedanken:

Halte alles einfach. Wenn Sie keine Millionen von Aufgaben haben, brauchen Sie keine optimierte Datenstruktur (außer Stolz oder der Drang nach voreiliger Optimierung).

Vermeiden Sie relative Zeiten. Verwenden Sie ein absolutes internes Häkchen. Wenn Sie eine Aufgabe hinzufügen, legen Sie die Option "Nächstes Mal ausführen" auf den aktuellen Tick-Wert fest. Fügen Sie es der Liste hinzu, sortieren Sie die Liste nach der Zeit.

Wenn Sie nach Aufgaben suchen, beginnen Sie am Anfang der Liste und wählen Sie alles aus, was ein Zeit & lt; = aktuelles Häkchen hat, führen Sie die Aufgabe aus.

Sammeln Sie alle Aufgaben in einer anderen Liste. Nachdem alle ausgeführt wurden, berechnen Sie das "run next time" basierend auf dem aktuellen Tick und dem Inkrement (damit Sie keine Tasks erhalten, die eine Schleife bilden), fügen Sie alle zur Liste hinzu und sortieren Sie.

    
Aaron Digulla 09.09.2011 14:42
quelle
1

Sehen Sie sich an, wie DelayQueue eine PriorityQueue verwendet, um eine solche geordnete Liste von Ereignissen zu verwalten. DelayQueue arbeitet mit Echtzeit und kann daher die in Condition und LockSupport verfügbaren zeitgesteuerten Wartemethoden verwenden. Sie könnten etwas wie ein SyntheticDelayQueue implementieren, das sich wie DelayQueue verhält, aber Ihren eigenen synthetischen Zeitdienst verwendet. Sie müssten natürlich die zeitgesteuerten Warte- / Signalisierungsmechanismen ersetzen, die kostenlos mit dem jdk geliefert werden, und dies ist möglicherweise nicht einfach zu tun.

    
Matt 09.09.2011 14:42
quelle
1

Wenn ich es tun müsste, würde ich eine einfache Warteschlange (Linked-List-Variante) erstellen. Diese Warteschlange würde eine dynamische Datenstruktur (beispielsweise eine einfache Liste) enthalten, die alle Aufgaben enthält, die erledigt werden müssen. Bei jedem Zeitintervall (oder Zeitschritt) liest der Prozess den ersten Knoten der Warteschlange und führt die Anweisungen aus, die er in der Liste dieses Knotens findet. Am Ende jeder Ausführung würde es die Neuterminierung berechnen und die neue Ausführung zu einem anderen Knoten in der Warteschlange hinzufügen oder Knoten bis zu dieser Position erstellen, bevor die Anweisung in diesem Knoten gespeichert wird. Der erste Knoten wird dann entfernt und der zweite Knoten (jetzt der erste) wird beim nächsten Zeitschritt ausgeführt. Dieses System würde auch nicht erfordern, dass ganze Zahlen verfolgt werden und alle benötigten Datenstrukturen in der Java-Sprache gefunden werden. Dies sollte Ihr Problem lösen.

    
Steinin 09.09.2011 14:56
quelle
0

Verwenden Sie einen ScheduledExecutorService . Es hat alles, was Sie brauchen, direkt eingebaut. So einfach ist es zu verwenden:

%Vor%     
Bohemian 09.09.2011 14:31
quelle

Tags und Links