Notice
Recent Posts
Recent Comments
Link
반응형
관리 메뉴

쿵야지식떨이

[Spring] 비동기 처리 @Async 적용 (3) - Blocking과 Non-Blocking 본문

Spring

[Spring] 비동기 처리 @Async 적용 (3) - Blocking과 Non-Blocking

김쿵야 2024. 3. 1. 20:53
반응형

동기와 비동기에 대해 정리를 하다 보면 Blocking과 Non-Blocking이라는 개념이 계속 나오게 된다. 맨 처음 글에서 정리했던 동기와 비동기를 간단하게 다시 보면서 Blocking과 Non-Blocking을 연관 지어 정리해보려 한다. 


 

📚Blocking

  • 자신의 작업을 진행하다가 다른 주체의 작업이 시작되면 다른 작업이 끝날 때까지 기다렸다가 자신의 작업을 시작하는 것.
  • 특정 작업이 완료될 때까지 실행 스레드가 대기 상태에 머무르는 것이다. 
  • 보통 파일을 읽거나 데이터베이스 쿼리를 실행하는 등의 I/O 작업이 일반적으로 Blocking 작업이다.

📚Non-Blocking

  • 다른 주체의 작업에 관련 없이 자신의 작업을 하는 것.
  • 작업이 완료될 때까지 스레드가 대기 상태에 머무르지 않고 작업이 완료되면 알림을 받거나 작업의 결과를 가져올 수 있는 방법을 제공한다.

 

📖Synchronous & Asynchronous

  • 한 작업이 다른 작업을 호출하는 경우, 호출되는 함수의 작업 완료 여부를 누가 신경을 쓰는지에 따라 나뉜다.
  • "신경 쓴다"는 방법으로 끝났으면 방법 2가지가 있다. 
    • 끝났다는 말을 들을 때까지 기다리기
    • 끝났는지 계속 물어보기

 

📚 Synchronous(동기)

  • 호출하는 함수가 작업 완료 여부를 확인한다.
  • 호출하는 함수는 호출되는 함수의 작업 완료 여부 또는 작업 완료 후 Return을 기다리고 있다.
  • 또는 주기적으로 계속 물어본다.
  • 즉, 작업 A가 끝날 때까지 다른 작업을 수행하지 않는 경우.

📚 Asynchronous(비동기)

  • 호출하는 함수가 작업 완료 여부를 신경 쓰지 않는다. 
  • 호출하는 함수에게 Callback을 전달해서 작업을 완료하면 실행하도록 한다.
  • 기다리지도, 물어보지도 않는다.
  • Asynchronous를 구현하기 위해 호출된 함수의 작업은 별도의 thread로 빼서 실행하며 완료되면 호출한 함수에게 알려준다.
  • 즉, 작업 A가 아직 끝나지 않았어도 작업 B를 수행할 수 있는 경우.
더보기
  • 예를 들어, 파일을 읽는 작업을 수행할 때, Blocking과 Synchronous 방식으로 처리하면 해당 파일을 모두 읽을 때까지 다른 작업을 수행하지 못하고 대기 하게 된다.
  • 반면, Non-Blocking과 Asychronous 방식으로 처리하면 파일을 일부 읽은 후 다른 작업을 수행할 수 있다.
  • 이러한 차이점으로 인해 Non-Blocking과 Asynchronous 방식이 I/O 작업 처리에 있어서 더욱 효율적인 방식으로 적용될 수 있다. 

 

위의 4개의 개념을 합쳐서 다양한 경우를 볼 수 있다. 

1. Sync + Blocking / Async + Non-Blocking

Sync + Blocking

  • 가장 흔히 볼 수 있는 조합이다.
  • 함수가 다른 함수를 호출하고, 그 결과를 반환받아서 다음 작업을 이어나간다.

Async + Non-Blocking

  • 일반적인 비동기 함수의 동작 방식이다.
  • 함수가 다른 함수를 호출하고 바로 제어권을 반환받는다.
  • 제어권을 반환받은 함수는 호출된 함수의 작업 완료를 기다리지 않고 바로 다음 작업을 할 수 있다.

 

2. Sync + Non-Blocking

  • Non-Blocking : 제어권을 넘김
  • Sync : 결과를 돌려줄 때 결과와 순서에 관심이 있음
  • 함수가 다른 함수를 호출하고 호출된 함수는 작업을 시작하고 즉시 제어권을 반환한다.
    • 이때, 작업의 완료를 기다리지 않고 다음 작업을 이어나갈 수 있다. → Non-Blocking 방식
  • 호출된 함수의 작업 완료 여부를 확인하려면 호출하는 함수가 주기적으로 Polling 해야 한다.
    • 즉, 작업의 완료 여부를 확인하려면 주기적으로 작업 상태를 체크해야 한다는 의미다.   Sync 방식
  • 호출한 함수가 제어권을 바로 반환받아 다른 작업을 수행할 수 있음에도 여전히 호출된 함수의 완료 여부를 계속해서 확인하게 된다.

 

3. Async + Blocking

  • Blocking : 제어권을 넘기지 않음
  • Async : 결과를 돌려줄 때 결과와 순서에 관심 없음
  • 호출한 함수는 호출되는 함수의 작업 결과에 관심이 없음에도 호출되는 함수의 결과를 기다려야 한다. → Blocking 방식
  • 호출된 함수의 작업이 끝나고 Callback 함수가 호출되어 결과가 반환되고 나면 대기하고 있던 작업 함수를 호출한 함수는 다음 작업을 수행하게 된다. 
  • 위 방식은 큰 이점이 없어 잘 사용하지 않는다고 한다. 

흔히 얘기하는 동기/비동기는 Sync + Blocking과 Async + Non-Blocking 형태이다.

  • Sync+Non-Blocking과 Async+Blocking 은 개발할 때는 극히 드물지만 애플리케이션 자체에서 의도치 않게 두 조합이 나올 경우가 있어서 알아두어야 한다고 한다.
  • 제어권을 가지고 있느냐 없느냐 결과에 관심이 있느냐 없느냐를 기준으로 접근하여 살펴보면 된다.

그럼 비동기는 무조건 Non-Blocking일까? 

  • 비동기(Asynchronous) 방식이 작업이 완료되는 것을 기다리지 않고 바로 제어를 반환하므로 일반적으로 Non-Blocking 방식과 관련이 있는 것은 맞다.
  • 하지만 '비동기 방식이 무조건 Non-Blocking 방식인 것은 아니다.'
  • 비동기 방식에서도 작업을 수행하는 동안 일시적으로 Blocking이 발생할 수 있다. (비동기이지만 Blocking인 경우)
    • 더보기
      - Java의 Future.get() 메서드는 비동기 작업의 결과를 가져오는 메서드이다.
      - Future 객체는 비동기 작업의 결과를 담고 있지만 get() 메서드를 호출하면 결과가 준비될 때까지 Blocking 된다.
      - 즉, 비동기적으로 실행되는 작업의 결과를 가져오지만, 그 결과가 준비될 때까지 현재 스레드를 Blocking 하는 방식으로 동작한다. 
  • Non-Blocking 방식에서도 항상 비동기 방식인 것도 아니다. (Non-Blocking이지만 동기인 경우)
    • 더보기
      - spring의 ListenableFuture는 동기적으로 작업을 수행하지만 작업의 완료를 기다리지 않고 다음 작업을 수행할 수 있다. 
      - ListenableFuture의 addCallback 메서드를 이용하면, 작업의 결과를 받아 처리하는 callback을 등록할 수 있다.

      - callback이 등록되면 작업이 완료될 때까지 기다리지 않고 바로 다음 작업을 수행할 수 있다. 
  • 따라서 비동기와 Non-Blocking은 서로 관련은 있지만 항상 같은 의미를 가지는 것은 아니다. 

 

 

참고

https://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/

반응형