[개인 공부 기록] 동기와 비동기의 차이 (블로킹과 논블로킹)
feat. focusing on Asynchronous
오랜만에 써보는 블로그 글..
기록의 중요성은 항상 느끼고 있지만 부족함에 안타까울 뿐
📌 동기 / 비동기 간 비교 분석
동기 (Synchronous) | 비동기 (Asynchronous) | |
정의 | 데이터의 요청과 결과가 한 자리에서 동시에 일어나는 것 | 데이터의 요청과 결과가 한 자리에서 동시에 일어나는 것이 아님 |
요청 후 대기 | O → 요청을 하면 응답이 올때까지 다른 활동을 할 수 없고 기다려야만 한다. | X → 요청을 한 후 응답을 계속 기다리지 않아도 되고 다른 요청사항을 보내도 된다. |
설계 | 설계가 매우 간단하고 직관적 | 설계가 복잡함 |
장점 | 간단하고 직관적인 코드를 작성하기 쉬움 순차적으로 실행되어야 하는 작업이나 작업 간의 의존성이 높은 경우 유용 |
I/O 작업이나 네트워크 요청과 같이 시간이 오래 걸리는 작업에 유용 |
단점 | 각 작업의 완료를 기다리는 동안 전체 프로세스 성능이 저하될 수 있음 한 작업이 지연되면 다른 작업들도 모두 지연됨 |
복잡함 |
📌 동기 / 비동기 versus. 블로킹 / 논블로킹
앞선 동기 / 비동기 의 구분은 요청한 작업에 대해 완료 여부를 신경 써서 작업을 순차적으로 수행할지 아닌지,
블로킹 / 논블로킹 의 구분은 현재 작업이 블록되느냐 아니냐에 따라 다른 작업을 수행할 수 있는지 에 대한 관점
함수의 코드나 프로세스의 실행 흐름을 제어하는 ‘제어권’으로 이 둘을 명확히 구분
블로킹과 논블로킹은 호출된 함수가 호출한 함수에게 제어권을 바로 주느냐 안주느냐로 구분됨
제어권이 넘어가버리면 해당 스레드는 블로킹 되는 것
📌 Combination of 동기 / 비동기 and 블로킹 / 논블로킹
참고(굉장히 상세한 글)
👩💻 완벽히 이해하는 동기/비동기 & 블로킹/논블로킹
동기/비동기 & 블로킹/논블록킹 프로그래밍에서 웹 서버 혹은 입출력(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();
}
});
}
}
당분간 비동기 프로그래밍 관련해서 공부를 좀 이어나갈 것 같다.
딱 한가지 명심할 것은 꾸준하기...!
오늘도 즐거운 하루 되세요 :)