본문 바로가기
  • 시 쓰는 개발자
1일 1개념정리 (24년 8월~)/운영체제

1일1개 (22) - 동기 vs 비동기

by poetDeveloper 2024. 8. 31.

1일 1개념정리 24.08.09.금 ~ 

 

큰 결정에 큰 동기가 따르지 않을 때도 있다. 하지만 큰 결심이 따라야 이뤄낼 수 있다.

무조건 무조건 1일 1개의 개념 정리하기 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!


#22. 동기 vs 비동기

운영체제나, 아니면 웹공부 할 때에도 동기식 처리, 비동기식 처리 이런 단어가 많이 나온다. 동기화라는 단어에서 많이 봤을 것이다. 간단히 이야기하면 동기는 동시에 하는 거고, 비동기는 동시에 하지 않는 것인데 디테일한 부분을 더 알아보자. 

 

동기 (Synchronous)

동기 방식은 작업을 순차적으로 처리하는 방식이다. 쉽게 말하면 "동시에 일어난다"이다. 그래서 한 작업이 끝나기 전까지 다음 작업이 시작되지 않는다. 모든 작업이 차례대로 수행되고, 현재 작업이 완료될 때까지 다른 작업은 대기 상태에 있는다.

보통 돈과 관련된 중요한 일이나, 요청과 응답을 정확히 서로 확인해야할 때 즉 목적이 서로 같은 상황이면 동기식 처리를 할 수 있다. 예를 들면 내가 은행 점원에게 가서 돈 100만원 뺄 때 계속 의사소통을 해야지, 돈 빼다가 그 사이에 밥먹으러 가버리면 안된다.

ex1) 식당에서 커피 주문한 후 커피 나오기 전까지 물도 안먹고 앉지도 않고 핸드폰도 안하고 그냥 아무것도 안함. 커피 받을 때까지 안움직임.

  • 장점 : 설계가 간단하고 직관적이라 예측하기 쉽고 디버깅도 용이함
  • 단점 : 근데 작업 끝날 때까지 기다려야하므로 속도가 느려질 수 있다. 그리고 이거를 계속 기다리는 것 자체가 자원 낭비이다. 난 다른 일 할 수 있는데 커피를 기다리느라 일 못하고 있음.

비동기 (Asynchronous)

비동기는 그럼 동기의 반대겠지요? 비동기 방식은 동시에 일어나지 않는 것인데, 한 작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있다. A-B 작업하다가, A를 기다리지 않고 B는 C라는 새로운 작업을 시작하는 것이다. 근데 계속 C랑만 작업할 수는 없고, A 작업 결과를 가지고 또 일해야하니까 A가 알람 보내면 그때 다시 가서 작업한다. 비동기 처리 방식은 특히 네트워크 통신이나 파일 I/O처럼 지연 시간이 큰 작업에서 매우 유용하다.

동기는 서로 같은 상황에서 유용하다고 했는데, 비동기는 반대로 서로 다른 상황일 때 유용하다. 예를 들어 난 커피를 주문했고, 커피 만드는 일은 내 일이 아니니까 굳이 그 자리에서 기다릴 필요 없다.

ex1) 식당에서 커피를 주문하고, 그 커피가 준비되는 동안 물도 먹고 화장실도 가고 핸드폰도 함. 그리고 커피가 나오면 점원이 나왔다고 진동벨로 알려줌 (콜백)

ex2) 대용량 데이터 처리시 이걸 다 기다리는 것은 시간이 너무 오래걸리고 비효율적이므로 비동기로 처리할 수 있다.

ex3) 외부 API 요청시, 그 응답때문에 서버가 기다릴 순 없다. 그래서 비동기처리 적용해서 응답을 기다리지 않고 다른 작업을 수행한다.

  • 장점 : 여러 작업을 병렬적으로 처리할 수 있어서 효율적이다. 안기다려도 되니까 특정 작업이 오래 걸리더라도 다른 작업을 방해하지 않아서 자원 효율적이다.
  • 단점 : 콜백처리도 해야하고 그래서 동기식 처리보다 복잡하고 어려움.

동기 / 비동기 처리 방법

Spring에서 동기처리, 비동기처리를 어떤 식으로 하고있을까 ?? 그리고 비동기 때는 작업에 대한 알람을 줘야한다고 했는데, 구체적으로 무슨 소리인지 Spring 예제로 알아보자.

 

동기처리 in Spring

일단, 기본적으로 Spring에서 메소드 호출은 동기식으로 처리된다. 컨트롤러에서 서비스 로직을 호출하면 서비스가 완료될 때까지 컨트롤러는 대기하게 된다.

 

비동기처리 in Spring

그럼 기본이 동기면, 비동기는 우리가 어떤 처리를 해줘야한다는 소리일텐데, 이는 @Async를 통해 처리할 수 있다. 이 어노테이션을 쓰면 메소드가 비동기적으로 실행된다. 이때 메소드는 별도의 스레드에서 실행되고 호출한 메소드는 즉시 반환된다.

@Service
public class AsyncService {

    @Async
    public CompletableFuture<String> performTask() {
        // 긴 작업 수행
        try {
            Thread.sleep(2000); // 2초 대기
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return CompletableFuture.completedFuture("Task Completed");
    }
}

@RestController
@RequiredArgsConstructor
public class AsyncController {
    private final AsyncService asyncService;

    @GetMapping("/async-task")
    public CompletableFuture<ResponseEntity<String>> executeAsyncTask() {
        return asyncService.performTask()
                           .thenApply(ResponseEntity::ok);  // 비동기적으로 서비스 호출
    }
}

위 코드에서 AsyncService의 performTask() 메소드는 비동기적으로 실행되므로 별도의 스레드에서 실행되고, 호출한 executeAsyncTask() 메소드는 즉시 반환되고, 작업이 완료되면 결과를 반환한다.

 

정리

  • 동기 : 작업들 순서 지켜야하고 이전 작업이 완료되야만 다음 작업이 진행되어야하는 상황에서 용이함
  • 비동기 : 작업들이 독립적으로 수행돼도 되고, 동시에 여러 작업 처리해서 효율성 올려야할 때 용이함