비동기와 동기가 뭔데요

LTT·2024년 11월 1일

Introduce


이전 포스트들에는 언급이 되어있는 비디오 업로드 서버 개발에 사용했던 비동기(Async) 방식에 대한 개념을 간단하게 정리해보자.

Async vs Sync 비교


Sync (동기)

: 호출-응답 이 동시에 일어나는 것을 의미. 이 말은 작업이 동시 발생하는 것이 아니라,

  • 함수를 호출한 지점에서 응답을 받는다.

  • A 함수가 B 함수를 호출할 때, B함수의 결과를 A함수가 처리

Async (비동기)

: 호출-응답 이 동시에 일어나지 않는 것을 의미.

  • 호출한 시점과 처리하고 응답한 시점이 같지 않아서, 함수를 호출했을 때 결과를 나중에 처리가 완료된 불특정한 시점에 받는다.

  • A 함수가 B 함수를 호출할 때, B 함수의 결과를 B 함수가 처리

    • Callback 이라고 볼 수도 있겠다.

각각의 장단점

  • 동기 방식
    • 설계가 매우 간단하고 직관적
    • 결과가 나올 때까지 아무것도 못하고 대기
  • 비동기 방식
    • 동기보다 설계가 훨씬 복잡함
    • 결과가 주어지는 데에 시간이 오래 걸리더라도 그 시간 동안 다른 작업 수행 가능 → 자원을 효율적으로 사용할 수 있음

Blocking vs Non-Blocking 비교


Blocking

: 함수를 호출했을 때 응답을 받기 위해 대기하고(블락되어있는) 있는 상태

  • A 함수가 B 함수를 호출할 때, B 함수에게 실행 제어권을 넘겨주어, B 함수가 종료될 때까지 쓰레드를 점유하는 방식

A 함수의 입장에서는 실행이 막혀(Block)있는 상태인 것이다.

Non-Blocking

: 함수를 호출했을 때 응답을 받을 때까지 다른 작업을 수행할 수 (블락되지 않는) 있는 상태

  • A 함수가 B 함수를 호출할 때, B 함수가 바로 실행 제어권을 다시 A 함수로 반환하며, B 함수가 실행되는 동안 다른 작업을 수행할 수 있게 되는 방식

A 함수의 입장에서는 실행이 막혀있지 않는 (Non-Block) 상태인 것이다.

조합


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

Sync-Blocking

위에서 개념 설명할 때 눈치 챘겠지만, 이 조합이 가장 일반적인 조합이다.

void main(String[] args) {
	String str = something(1, 3);
	
	System.out.println(str);
}

String something(int a, int b) {
	String str = "";
	
	for(int i = 0; i<3; i++) {
		str += "A"+a
	}
	
	return str;
}

그냥 흔한 일반적인 이런 코드다. 설명할게 없다.

Async-NonBlocking

간단한 API가 하나 있다고 가정해보자.

@EnableAsync
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

@Service
public class MessageService {

    @Async
    public void print(String message) {
        System.out.println(message);
    }
}

@RequiredArgsConstructor
@RestController
public class MessageController {

    private final MessageService messageService;

    @GetMapping("/messages")
    @ResponseStatus(code = HttpStatus.OK)
    public void printMessage() {
        for (int i = 1; i <= 100; i++) {
            messageService.print(i + "");
        }
    }
}

위에 사실 @Async 를 하나 붙여준 것이 전부다. Java에서 이것에 대해 다루려면 여기서는 안되니 다음에 시간이 되면 다뤄보도록 하겠다.

Async-NonBlocking방식은 약간 주제에 벗어나지만, 비동기를 다룬 이전 포스트인

에 간접적으로 언급한 적이 있다.

Sync-NonBlocking

내가 이 그림을 이해하기로는 이전에 설명한 API Polling같이 생겼다는 생각을 했다.

그런데 이게 무슨 소리일까… 간단하게 생각해보자.

Sync는 A 함수가 B 함수를 호출하면 B의 결과를 A가 처리한다.
Non-Blocking은 A 함수가 B 함수를 호출하면 실행 제어권을 B 함수가 바로 A 함수에게 반납한다.

A 함수의 입장에서, 실행 제어권 돌려받았으니 다른 작업을 수행할 수 있다. 하지만 언제 끝날지 모르는 B 함수의 작업 결과를 처리해야 한다.

그래서 어쩔 수 없이, 위의 그림처럼 B 함수에 계속해서 끝났냐고 물어보게 되는 상황이 나오는 것이다.

Async-Blocking

이건 진짜 생전 처음본다.

솔직히 이렇게 할 일도 없을 것 같고, 적절한 예시를 찾을 수도, 떠올릴 수도 없다… 넘어가도 될 듯하다.

결론


이들의 차이점에 대해 잘 몰랐던 사람들은 이 기회로 차이점에 대해 명확하게 인지하고,

각자 개발 상황에 맞는 올바른 전략을 채택하여 즐겁게 적용해보면 될 것 같다. 😃

profile
개발자에서 엔지니어로, 엔지니어에서 리더로

0개의 댓글