Was ist der Unterschied zwischen fester Rate und fester Verzögerung in der Spring Scheduled-Anmerkung?
Lesezeit: 8 Minuten
Adam
Ich implementiere geplante Aufgaben mit Spring, und ich sehe, dass es zwei Arten von Konfigurationsoptionen für die Zeit gibt, die die Arbeit ab dem letzten Aufruf erneut planen. Was ist der Unterschied zwischen diesen beiden Typen?
@Scheduled(fixedDelay = 5000)
public void doJobDelay() {
// do anything
}
@Scheduled(fixedRate = 5000)
public void doJobRate() {
// do anything
}
kuhajeyan
fixedRate : Lässt Spring die Aufgabe in regelmäßigen Abständen ausführen, auch wenn der letzte Aufruf möglicherweise noch ausgeführt wird.
fixedDelay : steuert speziell die nächste Ausführungszeit, wenn die letzte Ausführung beendet ist.
In Code:
@Scheduled(fixedDelay=5000)
public void updateEmployeeInventory(){
System.out.println("employee inventory will be updated once only the last updated finished ");
/**
* add your scheduled job logic here
*/
}
@Scheduled(fixedRate=5000)
public void updateEmployeeInventory(){
System.out.println("employee inventory will be updated every 5 seconds from prior updated has stared, regardless it is finished or not");
/**
* add your scheduled job logic here
*/
}
in jeder Methode, die ich verwende Thread.sleep(5000) zu warten 5s, aber ich sehe nicht, was anders ist
– Adam
9. August 2016 um 7:58 Uhr
genau das gleiche, ich glaube @nikhil7610 hat das richtig erklärt
– Ottercoder
11. Dezember 2017 um 10:40 Uhr
Der Unterschied besteht darin, dass, wenn „updateEmployeeInventory“ mit fixedRate mehr als 5 Sekunden dauert, Sie am Ende in 2 verschiedenen Threads 2 gleichzeitige Ausführungen der Methode ausführen, wobei fixedDelay Spring damit beginnt, die 5 Sekunden nach dem Ende der vorherigen Ausführung zu „zählen“.
– Glabler
15. Januar 2019 um 16:49 Uhr
Diese Antwort ist irreführend, siehe unten Antwort, die richtig ist.
– Sankarganesh Eswaran
22. März 2019 um 6:34 Uhr
@RanyAlbegWein Sie haben Recht, meine 3 Jahre alte Behauptung sollte nur gültig sein, wenn Async und EnableAsync bereitgestellt werden. Um die Vergangenheit zu verteidigen, ist es eine sehr schlechte Praxis, eine feste Rate zu haben, die mit der Zeit kleiner werden kann als die Ausführungszeit der geplanten Methode.
– Glabler
22. September 2021 um 15:14 Uhr
nikhil7610
„fixedRate“ : wartet X Millis ab dem Start der vorherigen Ausführung, bevor die nächste Ausführung gestartet wird. Wenn die aktuelle Ausführung das ‘fixedRate’-Intervall überschreitet, wird die nächste Ausführung in die Warteschlange gestellt, und dies erzeugt eine Reihe von laufenden Aufgaben, dh es werden mehrere Instanzen von Aufgaben ausgeführt.
private static int i = 0;
@Scheduled(initialDelay=1000, fixedRate=1000)
public void testScheduling() throws InterruptedException {
System.out.println("Started : "+ ++i);
Thread.sleep(4000);
System.out.println("Finished : "+ i);
}
Ausgabe:
Gestartet: 1
Fertig : 1 // nach 4 Sekunden
Gestartet: 2 // sofort ohne 1 Sek. zu warten, wie in der festen Rate angegeben
Fertig : 2 // nach 4 Sekunden
usw
„fixedDelay“ : wartet X Millis ab dem Ende der vorherigen Ausführung, bevor die nächste Ausführung gestartet wird. Unabhängig davon, wie lange die aktuelle Ausführung dauert, wird die nächste Ausführung gestartet, nachdem das Intervall „fixedDelay“ zur Endzeit der aktuellen Ausführung hinzugefügt wurde. Die nächste Ausführung wird nicht in die Warteschlange gestellt.
private static int i = 0;
@Scheduled(initialDelay=1000, fixedDelay=1000)
public void testScheduling() throws InterruptedException {
System.out.println("Started : "+ ++i);
Thread.sleep(4000);
System.out.println("Finished : "+ i);
}
Ausgabe:
Gestartet: 1
Finished : 1 // nach 4 Sekunden Started : 2 // wartet 1 Sekunde wie in fixedDelay angegeben Finished : 2 // nach 4 Sekunden Started : 3 // nach 1 Sekunde
usw
> “Wenn die aktuelle Ausführung das ‘fixedRate’-Intervall überschreitet, wird die nächste Ausführung in die Warteschlange gestellt, aber nur die nächste.” Dies scheint falsch zu sein, wenn es auf a ausgeführt wird ScheduledThreadPoolExecutor. Was ich in meinen Tests sehe, ist, dass der Executor Aufrufe in jedem Intervall in die Warteschlange stellt
– Johannes Rudolf
23. April 2019 um 14:35 Uhr
Ahmetcetin
fester Zinssatz: Dies wird verwendet, um die geplanten Jobs alle n Millisekunden auszuführen. Dabei spielt es keine Rolle, ob der Job bereits seine vorherige Runde beendet hat oder nicht.
feste Verzögerung: Es wird verwendet, um den geplanten Job sequentiell mit der angegebenen Verzögerungszeit von n Millisekunden zwischen den Runden auszuführen. Das heißt, die für den Job aufgewendete Zeit wirkt sich auf die Startzeit der nächsten Ausführung des geplanten Jobs aus.
Festpreis Beispiel:
@Scheduled(fixedRate = 5000)
public void runJobWithFixedRate() {
...
}
Nehmen wir an, der Job wird zum ersten Mal um 13:00:00 ausgelöst:
1. Lauf -> 13:00:00, Auftrag endet um 13:00:02
2. Lauf -> 13:00:05, Job endet um 13:00:08
3. Lauf -> 13:00:10, Auftrag endet um 13:00:16
4. Lauf -> 13:00:15, Auftrag endet um 13:00:18
fixedDelay Beispiel:
@Scheduled(fixedDelay = 5000)
public void runJobWithFixedDelay() {
...
}
Nehmen wir an, der Job wird zum ersten Mal um 13:00:00 ausgelöst:
1. Lauf -> 13:00:00, Auftrag endet um 13:00:02
2. Lauf -> 13:00:07, Job endet um 13:00:08
3. Lauf -> 13:00:13, Auftrag endet um 13:00:16
4. Lauf -> 13:00:21, Auftrag endet um 13:00:25
Wann verwenden “fester Zinssatz”: fixedRate ist angemessen, wenn die Größe des Arbeitsspeichers und des Thread-Pools voraussichtlich nicht überschritten wird. Wenn die eingehenden Aufgaben nicht schnell beendet werden, kann dies zu einer „Out of Memory-Ausnahme“ führen.
Wann verwenden “fixedDelay”:
Wenn jede laufende Aufgabe füreinander relevant ist und sie warten müssen, bis die vorherige beendet ist, ist fixedDelay geeignet. Wenn fixedDelay time sorgfältig eingestellt wird, wird es den laufenden Threads auch genug Zeit lassen, ihre Jobs zu beenden, bevor die neue Aufgabe beginnt
Eine Sache, die klargestellt werden sollte, ist die fixedRate bedeutet nicht, dass die Ausführung in einem bestimmten Zeitintervall beginnt.
Wenn eine Ausführung zu viel Zeit kostet (mehr als der Festpreis), wird die nächste Ausführung erst gestartet NACH der vorherige endet, es sei denn @Async und @EnableAsync sind vorgesehen. Die folgenden Quellcodes, die Teil von Spring’s sind ThreadPoolTaskScheduler Umsetzung erklären warum:
@Override
public void run() {
Date actualExecutionTime = new Date();
super.run();
Date completionTime = new Date();
synchronized (this.triggerContextMonitor) {
this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
if (!this.currentFuture.isCancelled()) {
schedule();
}
}
}
Sie können das erst sehen, nachdem die vorherige Aufgabe abgeschlossen ist (super.run()), wird die nächste Aufgabe geplant (schedule()). Mit @Async und @EnableAsync, super.run() ist eine asynchrone Funktion, die sofort zurückkehrt, sodass die nächste Aufgabe nicht warten muss, bis die vorherige tatsächlich beendet ist.
Ammar Akuri
Wir können eine geplante Aufgabe mit Spring ausführen @Scheduled Annotation, sondern basierend auf den Eigenschaften fixedDelay und fixedRate die Art der Ausführung ändert sich.
Das fixedDelay Eigentum stellt sicher, dass es eine Verzögerung von gibt n millisecond zwischen den finish time einer Ausführung einer Aufgabe und der start time der nächsten Ausführung der Aufgabe.
Diese Eigenschaft ist besonders nützlich, wenn wir sicherstellen müssen, dass immer nur eine Instanz der Aufgabe ausgeführt wird. Für abhängige Jobs ist es sehr hilfreich.
Das fixedRate Eigenschaft führt die geplante Aufgabe bei jedem aus n millisecond. Es wird nicht nach früheren Ausführungen der Aufgabe gesucht.
Dies ist nützlich, wenn alle Ausführungen der Aufgabe unabhängig sind. Wenn wir nicht erwarten, die Größe des Arbeitsspeichers und des Thread-Pools zu überschreiten, fixedRate sollte recht praktisch sein.
Wenn die eingehenden Aufgaben jedoch nicht schnell beendet werden, ist es möglich, dass sie mit einer „Out of Memory-Ausnahme“ enden.
Jinen Kothari
Feste Verzögerung : steuert speziell die nächste Ausführungszeit, wenn die letzte Ausführung beendet ist.
Fester Zinssatz : Lässt Spring die Aufgabe in regelmäßigen Abständen ausführen, auch wenn der letzte Aufruf möglicherweise noch ausgeführt wird.
Johannes Rudolf
Es scheint widersprüchliche Ratschläge zu geben, was diese Methoden bewirken. Eventuell kann sich das Verhalten je nach ändern taskScheduler oder Executor Bean, die im Frühlingskontext registriert ist. Ich fand die Antwort von @Ammar Akouri am nächsten.
Hier ist, was ich bei der Verwendung von a gefunden habe ScheduledThreadPoolExecutor (vollständige Testquelle unten angegeben)
weder fixedDelay Noch fixedRate Gleichzeitige Aufgabenausführungen zulassen
fixedDelay werde auf die warten Ende eines vorherigen Aufrufs, dann planen Sie einen neuen Aufruf zu einem festen Zeitpunkt in der Zukunft. Es wird daher nicht mehr als eine Aufgabe gleichzeitig in die Warteschlange stellen.
fixedRate plant für jede Periode einen neuen Aufruf. Es wird mehr als eine Aufgabe gleichzeitig in die Warteschlange stellen (möglicherweise unbegrenzt), aber Aufgaben werden niemals gleichzeitig ausgeführt.
Beispieltest (Kotlin/JUnit):
class LearningSchedulerTest {
private lateinit var pool: ScheduledExecutorService
@Before
fun before() {
pool = Executors.newScheduledThreadPool(2)
}
@After
fun after() {
pool.shutdown()
}
/**
* See: https://stackoverflow.com/questions/24033208/how-to-prevent-overlapping-schedules-in-spring
*
* The documentation claims: If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
* https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html#scheduleAtFixedRate-java.lang.Runnable-long-long-java.util.concurrent.TimeUnit-
*/
@Test
fun `scheduleAtFixedRate schedules at fixed rate`() {
val task = TaskFixture( initialSleep = 0)
pool.scheduleAtFixedRate({task.run()}, 0, 10, TimeUnit.MILLISECONDS )
Thread.sleep(15)
Assert.assertEquals(2, task.invocations.get())
Thread.sleep(10)
Assert.assertEquals(3, task.invocations.get())
Thread.sleep(10)
// 1 initial and 3 periodic invocations
Assert.assertEquals(4, task.invocations.get())
}
@Test
fun `scheduleAtFixedRate catches up on late invocations`() {
val task = TaskFixture(initialSleep = 30)
pool.scheduleAtFixedRate({task.run()}, 0, 10, TimeUnit.MILLISECONDS )
Thread.sleep(15) // we see no concurrent invocations
Assert.assertEquals(1, task.invocations.get())
Thread.sleep(10) // still no concurrent invocations
Assert.assertEquals(1, task.invocations.get())
Thread.sleep(10)
// 1 initial and 3 periodic invocations
Assert.assertEquals(4, task.invocations.get())
}
@Test
fun `scheduleWithFixedDelay schedules periodically`() {
val task = TaskFixture( initialSleep = 0)
pool.scheduleWithFixedDelay({task.run()}, 0, 10, TimeUnit.MILLISECONDS )
Thread.sleep(35)
// 1 initial and 3 periodic invocations
Assert.assertEquals(4, task.invocations.get())
}
@Test
fun `scheduleWithFixedDelay does not catch up on late invocations`() {
val task = TaskFixture( initialSleep = 30)
pool.scheduleWithFixedDelay({task.run()}, 0, 10, TimeUnit.MILLISECONDS )
Thread.sleep(35)
// 1 initial invocation, no time to wait the specified 10ms for a second invocation
Assert.assertEquals(1, task.invocations.get())
}
class TaskFixture(val initialSleep: Long) {
var invocations = AtomicInteger()
fun run() {
invocations.incrementAndGet()
if (invocations.get() == 1){
Thread.sleep(initialSleep)
}
}
}
}
Gibt es eine Möglichkeit, die gleichzeitige Ausführung zu ermöglichen?
– Greyshack
14. Juli 2019 um 10:46 Uhr
Es gibt: Sie müssen Scheduled with Async verwenden und sicherstellen, dass Ihr Executor nicht Single-Threaded ist.
– Greyshack
14. Juli 2019 um 11:05 Uhr
11458100cookie-checkWas ist der Unterschied zwischen fester Rate und fester Verzögerung in der Spring Scheduled-Anmerkung?yes