주니어 개발자 이망곰/개인 공부 기록

[개인 공부 기록] 동기와 비동기의 차이 (블로킹과 논블로킹)

이망곰 2024. 8. 30. 10:45

 

feat. focusing on Asynchronous

 

오랜만에 써보는 블로그 글..
기록의 중요성은 항상 느끼고 있지만 부족함에 안타까울 뿐

 

 

📌 동기 / 비동기 간 비교 분석

  동기 (Synchronous) 비동기 (Asynchronous)
정의 데이터의 요청과 결과가 한 자리에서 동시에 일어나는 것 데이터의 요청과 결과가 한 자리에서 동시에 일어나는 것이 아님
요청 후 대기 O → 요청을 하면 응답이 올때까지 다른 활동을 할 수 없고 기다려야만 한다. X → 요청을 한 후 응답을 계속 기다리지 않아도 되고 다른 요청사항을 보내도 된다.
설계 설계가 매우 간단하고 직관적 설계가 복잡함
장점 간단하고 직관적인 코드를 작성하기 쉬움
순차적으로 실행되어야 하는 작업이나 작업 간의 의존성이 높은 경우 유용
I/O 작업이나 네트워크 요청과 같이 시간이 오래 걸리는 작업에 유용
단점 각 작업의 완료를 기다리는 동안 전체 프로세스 성능이 저하될 수 있음
한 작업이 지연되면 다른 작업들도 모두 지연됨
복잡함

 

 

📌 동기 / 비동기 versus. 블로킹 / 논블로킹

앞선 동기 / 비동기 의 구분은 요청한 작업에 대해 완료 여부를 신경 써서 작업을 순차적으로 수행할지 아닌지,
블로킹 / 논블로킹 의 구분은 현재 작업이 블록되느냐 아니냐에 따라 다른 작업을 수행할 수 있는지 에 대한 관점  

 

함수의 코드나 프로세스의 실행 흐름을 제어하는 ‘제어권’으로 이 둘을 명확히 구분
블로킹과 논블로킹은 호출된 함수가 호출한 함수에게 제어권을 바로 주느냐 안주느냐로 구분됨
제어권이 넘어가버리면 해당 스레드는 블로킹 되는 것

 

 

📌 Combination of 동기 / 비동기 and 블로킹 / 논블로킹

참고(굉장히 상세한 글)

https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%B8%94%EB%A1%9C%ED%82%B9%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC

 

👩‍💻 완벽히 이해하는 동기/비동기 & 블로킹/논블로킹

동기/비동기 & 블로킹/논블록킹 프로그래밍에서 웹 서버 혹은 입출력(I/O)을 다루다 보면 동기/비동기 & 블로킹/논블로킹 이러한 용어들을 접해본 경험이 한번 쯤은 있을 것이다. 대부분 사람들은

inpa.tistory.com

 

 

📌 비동기 프로그래밍 사용하기

1. 비동기 API 호출 (CompletableFuture)

CompletableFuture 를 사용하여 HTTP 요청을 비동기적으로 수행하고, 결과를 처리할 수 있음
예를 들어, 서버에서 다른 API를 호출하여 데이터를 가져와야 할 때, 이 작업을 비동기적으로 수행하면 메인 스레드가 블로킹되지 않고 다른 작업을 계속할 수 있음

CompletableFuture.supplyAsync(() -> {

    // 비동기 HTTP 요청 수행
    return fetchDataFromApi(); // API 호출
    
}).thenAccept(response -> {

    // API 응답 처리
    System.out.println("API 응답: " + response);
});

 

2. 주기적인 데이터 백업 (ScheduledExecutorService)

일정 시간 후에 작업을 실행하거나, 일정 주기로 작업을 반복할 수 있도록 해줌
예를 들어, 서버에서 매일 자정에 데이터베이스 백업 작업을 수행해야 할 때 사용할 수 있음

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

Runnable backupTask = () -> {

    // 데이터 백업 작업 수행
    System.out.println("데이터베이스 백업 실행 중...");
};

// 매일 자정에 백업 실행
long initialDelay = calculateInitialDelay(); // 자정까지 남은 시간 계산
long period = 24 * 60 * 60; // 24시간 (초 단위)

scheduler.scheduleAtFixedRate(backupTask, initialDelay, period, TimeUnit.SECONDS);

 

3. 비동기 파일 읽기 (AsynchronousFileChannel)

파일을 비동기적으로 읽고 쓸 수 있게 해주는 API로, 이 방법을 사용하면 파일 입출력 작업이 완료될 때까지 기다리지 않고 다른 작업을 계속 할 수 있음
예를 들어, 서버가 대용량 로그 파일을 읽어야 할 때 이를 비동기적으로 수행하여 읽기 작업이 완료되면 콜백을 통해 결과를 처리할 수 있음

AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(Paths.get("largefile.txt"), StandardOpenOption.READ);

ByteBuffer buffer = ByteBuffer.allocate(1024);

fileChannel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
    
    @Override
    public void completed(Integer result, ByteBuffer attachment) {
        
        // 파일 읽기 완료 후 처리
        System.out.println("파일 읽기 완료: " + new String(attachment.array()));
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {
        
        // 읽기 실패 처리
        exc.printStackTrace();
    }
});

 

4. 긴 시간동안 실행되는 작업 (Servlet 3.0+ 비동기 요청 처리)

Servlet 3.0 이상에서는 비동기 요청 처리를 지원
예를 들어, 사용자가 웹 요청을 보냈을 때 해당 작업이 시간이 오래 걸리는 경우, 이를 비동기적으로 처리하여 사용자에게 빠르게 응답하고 작업이 완료되면 콜백을 통해 결과를 반환할 수 있음

@WebServlet(urlPatterns = "/asyncServlet", asyncSupported = true)
public class AsyncServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        AsyncContext asyncContext = request.startAsync();
        asyncContext.start(() -> {
            try {
                // 긴 시간 동안 실행되는 작업
                Thread.sleep(5000); // 예: 5초 동안의 작업
                response.getWriter().write("비동기 작업 완료!");
                asyncContext.complete();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}

 

당분간 비동기 프로그래밍 관련해서 공부를 좀 이어나갈 것 같다.

딱 한가지 명심할 것은 꾸준하기...!

오늘도 즐거운 하루 되세요 :)