programing

Spring Scheduled 주석에서 고정 속도와 고정 지연의 차이점은 무엇입니까?

javajsp 2023. 8. 12. 09:50

Spring Scheduled 주석에서 고정 속도와 고정 지연의 차이점은 무엇입니까?

Spring을 사용하여 스케줄링된 작업을 구현하고 있으며, 마지막 통화부터 다시 스케줄링되는 시간에 대한 두 가지 유형의 구성 옵션이 있는 것으로 확인되었습니다.이 두 가지 유형의 차이점은 무엇입니까?

 @Scheduled(fixedDelay = 5000)
 public void doJobDelay() {
     // do anything
 }

 @Scheduled(fixedRate = 5000)
 public void doJobRate() {
     // do anything
 }
  • fixedRate : 마지막 호출이 계속 실행 중인 경우에도 Spring이 작업을 주기적으로 실행하도록 합니다.
  • fixedDelay : 마지막 실행이 완료되는 다음 실행 시간을 구체적으로 제어합니다.

코드:

@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
     */
}

"fixedRate" : 이전 실행 시작부터 Xmillis를 기다린 후 다음 실행을 시작합니다.현재 실행이 'fixedRate' 간격을 초과하면 다음 실행이 대기열에 저장되고 여러 작업 인스턴스가 실행되는 일련의 작업이 생성됩니다.

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);
}

출력:

1.0%: 1
// 후: 1 // 4초 후
시작됨: 2 // 고정 속도로 지정된 대로 1초 동안 기다리지 않고 즉시 시작됨
// 후: 2 // 4초 후
등등 ㅠㅠ

"fixedDelay" : 이전 실행이 종료될 때부터 Xmillis를 기다렸다가 다음 실행을 시작합니다.현재 실행에 걸리는 시간은 상관없이 현재 실행의 종료 시간에 '고정 지연' 간격을 추가한 후 다음 실행을 시작합니다.다음 실행에서는 대기열에 표시되지 않습니다.

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);
}

출력:

1.0%: 1
1 후 // 완료:2 후 // 후 : 1 // 4초 후: 2 // 2 // 4초 후: 2 // 3 // 후: 3 // 1초 후: 3 // 1초 후: 3 // 1초 후: 3 // 1초 후: 1초 동안
등등 ㅠㅠ

고정 요금:예약된 작업을 n밀리초마다 실행하는 데 사용됩니다.작업이 이전 순서를 이미 마쳤는지 여부는 중요하지 않습니다.

고정 지연:이 명령은 턴 사이에 지정된 n밀리초의 지연 시간으로 예약된 작업을 순차적으로 실행하는 데 사용됩니다.즉, 작업에 소요된 시간은 예약된 작업의 다음 실행 시작 시간에 영향을 미칩니다.

고정 요금 예:

@Scheduled(fixedRate = 5000)
public void runJobWithFixedRate() {
...
}

작업이 처음으로 13:00:00에 트리거되었다고 가정합니다.

  • 번째 실행 -> 13:00:00, 작업이 13:00:02에 종료됩니다.
  • 2차 실행 -> 13:00:05, 작업이 13:00:08에 종료됩니다.
  • 3차 실행 -> 13:00:10, 작업이 13:00:16에 종료됩니다.
  • 4차 실행 -> 13:00:15, 작업이 13:00:18에 종료됩니다.

고정 지연 예:

@Scheduled(fixedDelay = 5000)
public void runJobWithFixedDelay() {
...
}

작업이 처음으로 13:00:00에 트리거되었다고 가정합니다.

  • 번째 실행 -> 13:00:00, 작업이 13:00:02에 종료됩니다.
  • 2차 실행 -> 13:00:07, 작업이 13:00:08에 종료됩니다.
  • 3차 실행 -> 13:00:13, 작업이 13:00:16에 종료됩니다.
  • 4차 실행 -> 13:00:21, 작업이 13:00:25에 종료됩니다.

"fixedRate"를 사용할 때: fixedRate는 메모리와 스레드 풀의 크기를 초과하지 않을 것으로 예상되는 경우 적절합니다.들어오는 작업이 빨리 완료되지 않으면 "메모리 부족 예외"로 끝날 수 있습니다.

고정 지연을 사용하는 경우:실행 중인 모든 작업이 서로 관련되어 있고 이전 작업이 완료될 때까지 기다려야 하는 경우 고정 지연이 적합합니다.고정 지연 시간을 신중하게 설정하면 실행 중인 스레드가 새 작업을 시작하기 전에 작업을 완료할 수 있는 충분한 시간도 제공됩니다.

한 가지 분명히 해야 할 것은fixedRate실행이 특정 시간 간격으로 시작된다는 의미는 아닙니다.

한 실행에 너무 많은 시간이 소요되는 경우(고정 속도보다 많은 시간), 다음 실행은 이전 실행이 완료된 에만 시작됩니다.@Async그리고.@EnableAsyncSpring's Spring의 일부인 은 Spring'spring's spring's에 속합니다.ThreadPoolTaskScheduler이유를 합니다. 다음과 같습니다.

@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();
        }
    }
}

에야 알 수.super.run()되어 있습니다().schedule())와 함께.@Async그리고.@EnableAsync,super.run()는 즉시 반환되는 비동기 함수이므로 다음 작업은 이전 작업이 실제로 완료될 때까지 기다릴 필요가 없습니다.

Spring의 주석을 사용하지만 속성을 기반으로 예약된 작업을 실행할 수 있습니다.fixedDelay그리고.fixedRate실행의 성격이 변합니다.

fixedDelay는 자은다지있확인합다니을음연의 확인합니다.n millisecondfinish time과 업의실과의.start time작업을 다음에 실행할 수 있습니다.

이 속성은 작업의 인스턴스를 하나만 항상 실행해야 할 때 특히 유용합니다.의존적인 직업의 경우, 그것은 꽤 도움이 됩니다.

fixedRate합니다.n millisecond작업의 이전 실행은 확인하지 않습니다.

이 기능은 태스크의 모든 실행이 독립적인 경우에 유용합니다.메모리와 스레드 풀의 크기를 초과하지 않을 것으로 예상하면,fixedRate아주 편리할 겁니다

그러나 들어오는 작업이 빨리 완료되지 않으면 "메모리 부족 예외"로 끝날 수 있습니다.

고정 지연 : 마지막 실행이 완료되는 다음 실행 시간을 구체적으로 제어합니다.

Fixed Rate : 마지막 호출이 계속 실행 중인 경우에도 Spring이 작업을 주기적으로 실행하도록 합니다.

이 방법들이 무엇을 하는지에 대한 상반된 조언이 있는 것 같습니다.아마도 행동은 그것에 따라 바뀔 수 있습니다.taskScheduler또는Executorspring 컨텍스트에 등록되어 있습니다.저는 @Ammar Akouri의 대답이 가장 가깝다는 것을 알았습니다.

다음은 사용할 때 발견한 내용입니다.ScheduledThreadPoolExecutor(아래에 완전한 테스트 소스 제공)

  • 둘 다 아니다.fixedDelay도 아니다fixedRate동시 태스크 실행 허용
  • fixedDelay이전 호출이 종료될 때까지 기다린 다음 이후에 정해진 시간에 새 호출을 예약합니다.따라서 한 번에 둘 이상의 작업을 대기열에 넣지 않습니다.
  • fixedRate주기마다 새 호출을 예약합니다.한 번에 둘 이상의 작업을 대기열에 넣지만(잠재적으로 제한되지 않음) 작업을 동시에 실행하지는 않습니다.

표본 검정(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)
        }
      }
    }
}

fixedDelay 속성을 사용하면 작업 실행 완료 시간과 다음 작업 실행 시작 시간 사이에 n밀리초의 지연이 발생합니다.

이 속성은 작업의 인스턴스를 하나만 항상 실행해야 할 때 특히 유용합니다.의존적인 직업의 경우, 그것은 꽤 도움이 됩니다.

fixedRate 속성은 스케줄링된 작업을 n밀리초마다 실행합니다.작업의 이전 실행은 확인하지 않습니다.

이 기능은 태스크의 모든 실행이 독립적인 경우에 유용합니다.메모리와 스레드 풀의 크기를 초과하지 않을 것으로 예상하면 fixedRate가 매우 유용할 것입니다.

그러나 들어오는 작업이 빨리 완료되지 않으면 "메모리 부족 예외"로 끝날 수 있습니다.

자세한 내용은 https://www.baeldung.com/spring-scheduled-tasks 를 참조하십시오.

몇몇 응답자들은 작업이 여전히 실행 중인 경우 고정 속도가 병렬 프로세스를 실행할 것이라고 말했습니다.이것은 사실이 아닌 것 같습니다. 배들둥 기사에서 그들은 말합니다.

이 경우 마지막 실행이 종료되고 다음 실행이 시작될 때까지의 기간이 고정됩니다.작업은 항상 이전 작업이 완료될 때까지 기다립니다.

제가 직접 테스트해 봤습니다.예약 속도가 3초에 불과하더라도 코드는 작업이 완료될 때까지 5초 동안 기다립니다.

  AtomicInteger runCount = new AtomicInteger(0);

  /** Sleeps for 5 seconds but pops every 3 seconds */
  @Scheduled(fixedRate = 3000)
  public void runTransactionBillingJob() throws InterruptedException {
    log.info("{}: Popping", runCount);
    Thread.sleep(5000);
    log.info("{}: Done", runCount);
    runCount.incrementAndGet();
  }

어떤 것이 생산합니까?

""10:52:26.003 [pls-scheduled-task-pool-1] INFO  c.p.c.s.i.InvoiceSettingsServiceImpl.runTransactionBillingJob 38  - 0: Done
""10:52:26.004 [pls-scheduled-task-pool-1] INFO  c.p.c.s.i.InvoiceSettingsServiceImpl.runTransactionBillingJob 36  - 1: Popping
""10:52:31.015 [pls-scheduled-task-pool-1] INFO  c.p.c.s.i.InvoiceSettingsServiceImpl.runTransactionBillingJob 38  - 1: Done
""10:52:31.017 [pls-scheduled-task-pool-1] INFO  c.p.c.s.i.InvoiceSettingsServiceImpl.runTransactionBillingJob 36  - 2: Popping
""10:52:36.023 [pls-scheduled-task-pool-1] INFO  c.p.c.s.i.InvoiceSettingsServiceImpl.runTransactionBillingJob 38  - 2: Done
""10:52:36.024 [pls-scheduled-task-pool-1] INFO  c.p.c.s.i.InvoiceSettingsServiceImpl.runTransactionBillingJob 36  - 3: Popping
""10:52:41.032 [pls-scheduled-task-pool-1] INFO  c.p.c.s.i.InvoiceSettingsServiceImpl.runTransactionBillingJob 38  - 3: Done
""10:52:41.033 [pls-scheduled-task-pool-1] INFO  c.p.c.s.i.InvoiceSettingsServiceImpl.runTransactionBillingJob 36  - 4: Popping

언급URL : https://stackoverflow.com/questions/38842507/whats-the-difference-between-fixed-rate-and-fixed-delay-in-spring-scheduled-ann