CS

동기, 비동기

baek-dev 2025. 2. 6. 19:39

동기(Synchronous)와 비동기(Asynchronous)는 프로그램 실행 방식에서 작업의 처리 순서와 제어 흐름이 어떻게 이루어지는지를 정의하는 개념입니다. 이 개념은 주로 프로세스, 쓰레드, 함수 호출, 네트워크 요청 등에서 사용됩니다.

 

1. 동기(Synchronous)

  • 정의: 작업을 순차적으로 실행하며, 하나의 작업이 완료될 때까지 대기한 후 다음 작업을 실행하는 방식.
  • 특징:
    1. 작업의 결과를 기다렸다가 다음 작업을 실행함.
    2. 실행 순서가 직관적이며, 디버깅과 구현이 상대적으로 쉬움.
    3. 작업 완료 전까지 다음 작업으로 진행하지 않으므로 성능이 느려질 수 있음.

동작 방식

  1. 요청 → 대기 → 결과 반환 → 다음 작업.
  2. 작업 A가 끝날 때까지 작업 B는 시작되지 않음.

비유

  • “음식점에서 주문한 음식을 모두 조리한 뒤에야 고객에게 서빙하는 방식.”
  • 요리사는 한 고객의 음식을 완성하기 전까지 다음 고객을 받지 않음.

장점

  • 코드의 흐름이 이해하기 쉬움.
  • 작업이 순차적으로 처리되므로 데이터 처리의 순서를 보장.

단점

  • 작업이 오래 걸리면 시스템 전체가 대기 상태가 됨.
  • 리소스 사용 효율성이 낮음.

 

예제 (Java):

public void synchronousExample() {
    System.out.println("작업 A 시작");
    System.out.println("작업 A 완료");

    System.out.println("작업 B 시작");
    System.out.println("작업 B 완료");
}

 

실행 결과:

작업 A 시작
작업 A 완료
작업 B 시작
작업 B 완료

2. 비동기(Asynchronous)

  • 정의: 작업을 병렬적으로 실행하며, 특정 작업이 완료될 때까지 대기하지 않고 다른 작업을 수행하는 방식.
  • 특징:
    1. 작업의 완료 여부와 관계없이 다음 작업을 바로 시작함.
    2. 비동기적으로 실행된 작업의 결과는 나중에 콜백(Callback) 함수나 이벤트를 통해 처리.
    3. CPU와 자원을 효율적으로 사용할 수 있어 성능이 좋아짐.

동작 방식

  1. 요청 → 다음 작업 실행 → 결과 반환(콜백 또는 이벤트).
  2. 작업 A와 작업 B가 동시에 진행될 수 있음.

비유

  • “음식점에서 여러 주문을 한 번에 받아 놓고, 준비되는 대로 고객에게 서빙하는 방식.”
  • 요리사는 각 고객의 요리를 병렬적으로 준비하며, 완료된 요리부터 전달함.

장점

  • 시스템 성능과 처리 속도 향상.
  • 리소스를 효율적으로 사용할 수 있음.

단점

  • 코드 흐름이 복잡해짐.
  • 디버깅과 예외 처리가 어려움.

 

예제 (Java, 비동기 작업):

import java.util.concurrent.CompletableFuture;

public void asynchronousExample() {
    System.out.println("작업 A 시작");

    CompletableFuture.runAsync(() -> {
        try {
            Thread.sleep(2000); // 작업 A 실행 중
            System.out.println("작업 A 완료");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });

    System.out.println("작업 B 시작");
    System.out.println("작업 B 완료");
}

 

실행 결과:

작업 A 시작
작업 B 시작
작업 B 완료
작업 A 완료 (2초 후)

3. 동기와 비동기의 차이점

구분 동기 (Synchronous) 비동기 (Asynchronous)
작업 방식 작업이 완료될 때까지 대기 후 다음 작업 실행 작업 완료 여부와 관계없이 즉시 다음 작업 실행
속도 느릴 수 있음 빠르고 효율적
제어 흐름 순차적, 직관적 병렬적, 복잡한 흐름
사용 사례 데이터베이스 트랜잭션, 파일 I/O 처리 네트워크 요청, UI 이벤트 처리

4. 주요 사용 사례

 

동기 사용 사례

  • 데이터베이스 트랜잭션: 데이터 처리 순서를 보장해야 함.
  • 파일 읽기/쓰기: 간단한 파일 작업에서 비동기가 불필요할 때.

 

비동기 사용 사례

  • 네트워크 요청: HTTP 요청 응답을 기다리지 않고 다른 작업 수행.
  • UI 이벤트 처리: 버튼 클릭, 스크롤 등.
  • 대용량 데이터 처리: 백그라운드에서 처리해야 할 작업(예: 로그 분석).

5. 추가 개념: 동기 비동기와 블로킹/논블로킹

 

동기/비동기블로킹/논블로킹은 서로 다른 개념이지만, 자주 함께 논의됨.

 

블로킹 (Blocking)

  • 호출된 작업이 완료될 때까지 호출자가 대기.
  • 비유: “전화가 연결될 때까지 수화기를 들고 기다리는 상황.”

 

논블로킹 (Non-Blocking)

  • 호출된 작업이 완료되지 않아도 즉시 반환하며, 작업이 완료되면 콜백으로 결과를 처리.
  • 비유: “전화가 연결되기를 기다리지 않고, 연결되면 알림을 받는 상황.”

 

차이점 정리

구분 동기 비동기
블로킹 작업이 완료될 때까지 대기 비동기로 요청 후 결과를 받기 전까지 대기
논블로킹 작업이 완료될 때까지 대기하지 않음 요청 후 작업과 무관하게 다른 작업 수행

요약

  1. 동기(Synchronous)는 작업 완료를 기다렸다가 다음 작업을 수행.
  2. 비동기(Asynchronous)는 작업 완료를 기다리지 않고 병렬적으로 작업을 수행.
  3. 동기는 간단하지만 느릴 수 있음, 비동기는 복잡하지만 효율적.
  4. 비동기 프로그래밍은 주로 네트워크 요청, 대량 데이터 처리, UI 이벤트 등에 사용됨.

 

Q1: 비동기 처리에서 발생할 수 있는 콜백 지옥(Callback Hell) 문제를 해결하기 위한 방법은 무엇인가?

 

1. CompletableFuture 활용

  • CompletableFuture는 Java 8에서 도입된 비동기 작업을 다루는 클래스입니다. 작업 체이닝(thenApply, thenCompose)을 사용해 콜백 중첩을 방지할 수 있다.
  • 예제:
CompletableFuture.supplyAsync(() -> {
    // 작업 A
    return "작업 A 결과";
}).thenApply(resultA -> {
    // 작업 B (A 결과 활용)
    return resultA + " + 작업 B 결과";
}).thenAccept(finalResult -> {
    // 최종 결과 처리
    System.out.println(finalResult);
});

 

2. @Async 활용

  • Spring에서 제공하는 @Async 애노테이션을 사용하면 비동기 작업을 간단히 관리할 수 있습니다. 반환값으로 CompletableFuture를 사용해 체이닝이 가능.
  • 예제:
@Async
public CompletableFuture<String> asyncMethodA() {
    return CompletableFuture.supplyAsync(() -> "작업 A 결과");
}

@Async
public CompletableFuture<String> asyncMethodB(String input) {
    return CompletableFuture.supplyAsync(() -> input + " + 작업 B 결과");
}

public void execute() {
    asyncMethodA().thenCompose(this::asyncMethodB)
                 .thenAccept(finalResult -> System.out.println(finalResult));
}

 

3. Reactor와 같은 라이브러리 사용

  • Reactor (Spring WebFlux)는 비동기 스트림을 처리하기 위해 설계된 라이브러리입니다. Mono와 Flux를 사용하면 비동기 작업의 체이닝이 간결해진다.
  • 예제:
Mono.just("작업 A 결과")
    .map(resultA -> resultA + " + 작업 B 결과")
    .doOnNext(finalResult -> System.out.println(finalResult))
    .subscribe();

 

 

Q2: 동기와 비동기를 사용해야 할 상황을 더 구체적인 사례로 구분하여 설명.

 

동기를 사용해야 하는 경우

  1. 데이터의 순서와 무결성이 중요한 경우
    • 예제: 데이터베이스 트랜잭션.
    • 주문 생성 후 결제 데이터를 기록하는 과정에서 순서가 보장되어야 함.
    • 예: Order를 저장한 후, Payment 테이블에 결제 정보를 저장.
    • 사용 이유: 데이터 불일치가 발생하면 심각한 문제를 유발할 수 있으므로 동기 처리가 적합.
  2. 단일 작업이 오래 걸리지 않는 경우
    • 예제: 단순한 파일 읽기/쓰기.
    • 로그 파일을 저장하는 작업.
    • 사용 이유: 간단한 작업에서는 비동기 처리가 오히려 복잡성을 증가시킬 수 있음.

 

비동기를 사용해야 하는 경우

  1. I/O 요청이 많은 경우
    • 예제: REST API 호출이나 데이터베이스에서 대량의 데이터를 조회.
    • 예: 외부 API를 호출해 환율 정보를 가져오는 작업.
    • 사용 이유: 네트워크 요청은 대기 시간이 길기 때문에, 비동기로 처리해 리소스를 효율적으로 사용.
  2. 백그라운드 작업
    • 예제: 이메일 발송, 이미지 처리.
    • 사용자 요청에 응답한 후, 이메일 발송은 백그라운드에서 처리.
    • 사용 이유: 사용자 경험을 향상시키고, 비동기적으로 작업을 완료.
  3. 다중 사용자 요청 처리
    • 예제: 웹 서버의 요청 처리.
    • 서버가 많은 요청을 병렬로 처리할 때 비동기가 효율적.
    • 사용 이유: 각 요청이 비동기로 처리되면 시스템의 처리량이 증가.

 

Q3: 비동기 처리를 지원하는 Java의 CompletableFuture와 Spring의 @Async의 차이점은 무엇인가?

항목 CompletableFuture Spring @Async
정의 Java 8에서 제공하는 표준 비동기 API Spring에서 제공하는 비동기 작업을 간단히 처리하는 애노테이션
스레드 풀 관리 Executor를 명시적으로 설정 가능 Spring이 자동으로 스레드 풀을 관리
사용 방식 체이닝(thenApply, thenCompose) 등을 통해 작업 조합 가능 비동기 메서드 호출 시 작업을 분리하여 실행
복잡한 작업 처리 복잡한 비동기 로직에 적합 상대적으로 간단한 비동기 작업에 적합
의존성 순수 Java 환경에서 동작 Spring Context가 필요

 

예제 비교

 

1. CompletableFuture

사용 방식:

CompletableFuture.supplyAsync(() -> "작업 A 결과")
    .thenApply(resultA -> resultA + " + 작업 B 결과")
    .thenAccept(System.out::println);

 

사용 사례:

순수 Java 환경에서 비동기 작업을 체이닝하거나 병렬 작업이 필요할 때.

 

2. Spring @Async

사용 방식:

@Async
public CompletableFuture<String> asyncMethodA() {
    return CompletableFuture.supplyAsync(() -> "작업 A 결과");
}

public void execute() {
    asyncMethodA().thenAccept(System.out::println);
}

 

사용 사례:

Spring 기반 애플리케이션에서 간단히 비동기 작업을 구현하고, 스레드 관리까지 Spring에 맡기고 싶을 때.

 

요약

1. 콜백 지옥 문제는 CompletableFuture, @Async, 또는 Reactor를 사용해 해결.

2. 동기는 데이터 순서 보장이 필요할 때, 비동기는 성능 최적화가 필요한 I/O 작업 및 병렬 처리가 필요한 상황에서 사용.

3. CompletableFuture는 복잡한 비동기 로직에 적합하며, @Async는 Spring 환경에서 간단한 비동기 작업에 적합.

 

 

 

 

출처 : ChatGPT

'CS' 카테고리의 다른 글

git branch 별 차이 (dev, origin dev, origin/dev)  (0) 2025.02.11
소프트딜리트 Soft Delete, 하드딜리트 Hard Delete  (1) 2025.02.08
JMeter 성능테스트  (1) 2025.02.04
DBMS, RDBMS, RDB  (3) 2025.02.03
Redis 레디스  (0) 2025.02.01