프로그래밍을 수행하다보면 동기/비동기와 블로킹/논블로킹에 대해서 접하게 된다.
동기/비동기는 프로세스 수행방식과 관련해서 많이 접했던 것 같고 블로킹/논블로킹은 I/O와 DB 관련해서 배울 때 많이 접했던 것 같다. 이 2가지는 완전히 다른 개념인데 우리는 둘을 혼동해서 쓰는 경우가 많다.
때문에 개념이 명확이 알고 있어야 코딩도 잘할 수 있다고 생각하기 때문에 이번 기회에 확실히 개념을 집고 넘어가고자 한다.
개념 정리는 아래 블로그를 많이 참조하였다.
동기는 프로세스를 순차적으로 처리하는 것이다. 프로세스 순서가 A -> B -> A 라고 가정한다면 B는 A가 완료된 후 실행되고 B가 완료되면 A를 실행한다.
비동기는 반대로 프로세스를 순차적으로 실행하지 않고 처리하는 것이다. 동기에서는 앞에 프로세스가 완료되어야만 다음 프로세스를 실행했지만 비동기에서는 다음 프로세스가 안료될 때까지 기다리지 않고 실행한다. 따라서 완료 순서도 보장되지 않는다. A다음에 B가 실행되었더라도 B가 더 짧게 수행하여 A보다 일찍 종료될 수 있다.
아래 그림은 위 블로그에서 참고하였다.
작업을 순서대로 처리하지 않는다는 것은 I/O작업과 같은 느린 작업이 발생할 때, 기다리지 않고 다른 작업을 처리하면서 동시에 처리하여 멀티 작업을 진행할 수 있다는 것이다. 이는 전반적인 시스템 성능 향상에 도움을 줄 수 있다.
수행이 오래걸리는 작업이 있다고 한다면 동기적으로 수행시 해당 작업이 완료될 때까지 기다려야 하고 다른 요청을 처리하지 못하므로 대규모 이벤트나 트래픽이 발생시 성능이 저하될 수 있다.
하지만 비동기 방식으로 수행하면 다른 요청을 '동시에 처리'할 수 있게 된다. 이렇게 비동기 방식으로 사용하면, 대규모 트래픽에서도 안정적으로 동작할 수 있다.
동기/비동기가 전체적인 작업에 대한 순차적인 흐름 유무라면, 블로킹/논블로킹은 전체적인 작업의 흐름자체를 막냐 안 막냐로 볼 수 있다.
예를 들어, 파일을 읽는 작업이 있을 때, 블로킹 방식으로 읽으면 파일을 다 읽을 때까지 대기하고, 논블로킹 방식으로 읽으면 파일을 다 읽지 않아도 다른 작업을 할 수 있다.
결국은 동기/비동기나 블로킹/논블로킹이나 추구하는 결과로만 보자면 동시에 다른 작업을 수행한다는 점에서 그게 것이라고 볼 수도 있지만 염연히 나타내는 의미는 다르다.
동기/비동기는 출력 순서와 관련된 개념이고 블로킹/논블로킹은 병렬 실행과 관련된 개념이다. 제어권이라는 개념에 대해서 알면 이 둘의 차이를 더 명확히 알 수 있다.
제어권은 간단히 말해서 함수의 코드나 프로세스의 실행 흐름을 제어할 수 있는 권리같은 것이다. Blocking과 Non-Blocking은 호출된 함수가 호출한 함수에게 제어권을 바로 주느냐 안주느냐로 구분된다. 제어권이 넘어가버리면 해당 스레드는 블로킹되게 된다.
반대로 Non-blocking 방식일 때는 제어권을 넘겨주지 않는다.
여기서 드는 생각이 A프로세스가 B프로세스의 완료여부를 알아야 할 때는 어떻게 해야할까? 동기식은 순차적으로 처리하고 블로킹은 완료되면 제어권을 넘겨준다. 하지만 비동기식이나 논블로킹일 때는 어떻게 알아야할 것인가?
다른 작업의 완료 여부나 결과에 대한 후처리를 위해 이용되는 방식이 콜백 함수이다. A함수에서 B함수를 논블로킹 방식으로 실행하였을 경우 B함수가 끝났을 때만 처리되어야 하는 로직이 있을 경우 콜백 함수를 이용한다.
콜백함수는 하나의 기술이지 개념이 아니다. 비동기 논블로킹을 구현하는 기술은 콜백 외에 여러가지가 있고 콜백은 그 중 하나이다. 동기/비동기, 블로킹/논블로킹 개념과 직접적인 관련은 없다.
이 둘의 정확한 차이를 알기 위해서는 두 가지 개념을 조합해보면 좀 더 이해하기 편할 것이다.
Sync + Blocking 조합은 다른 작업이 진행되는 동안 자신의 작업을 처리하고 않고(Blocking), 다른 작업의 완료 여부를 바로 받아 순차적으로 처리하는 (Sync) 방식이다.
실생활 동작예시
1. 팀장 : 사원1씨 업무 A 좀 해주세요
2. 사원1 : 네 알겠습니다.(A를 처리중)
3. 팀장 : (사원1이 A를 다할 때까지 아무일도 하지 않고 기다린다.)
4. 사원1 : 팀장님 A 업무 완료했습니다.
5. 팀장 : 수고했어요. 사원2씨 업무 B좀 해주세요
6. 사원2 : 네 알겠습니다.(B를 처리중)
7. 팀장 : (사원2가 B를 다할 때까지 아무일도 하지 않고 기다린다.)
8. 사원2 : 팀장님 B 업무 완료했습니다.
Async + Non-Bloacking 조합은 다른 작업이 진행되는 동안에 자신의 작업을 처리하고(Non Blocking), 다른 작업의 결과를 바로 처리하지 않아 작업 순서가 지켜지지 않는 (Async) 방식이다.
실생활 동작예시
1. 팀장: 사원1씨 A업무 좀 해주세요.(동시에 지시)
2. 팀장: 사원2씨 B업무 좀 해주세요.(동시에 지시)
3. 팀장: 사원3씨 c업무 좀 해주세요.(동시에 지시)
4. 팀장: 다른일을 해야지 ~
5. 사원2: 팀장님 B 모두 처리했습니다.(업무량에 따라 각 사원마다 완료하는 시간이 제각기 다를 수 있다.)
6. 사원1: 팀장님 A 모두 처리했습니다.
7. 사원3: 팀장님 C 모두 처리했습니다.
Sync + Non-Blocking 조합은 다른 작업이 진행되는 동안에도 자신의 작업을 처리하고 (Non Blocking), 다른 작업의 결과를 처리하여 작업을 순차대로 수행하는 (Sync) 방식이다.
실생활 동작예시
팀장이 업무 A, B, C를 사원 1, 2, 3에게 시키려고 한다. 그런데 업무 특성상 업무 A를 완료해야 업무 B를 할 수 있고, 업무 B를 완료해야 업무 C를 할 수 있다.
1. 팀장: 사원1씨 업무 A 좀 해주세요
2. 사원1: 네 알겠습니다.(A를 처리중)
3. 팀장: 다음 업무 B를 하려면 A가 완료되야 하는데.. 사원1씨 다했어요?
4. 사원1: 아직이요 A처리중입니다.
5. 팀장: 사원1씨 다했어요?
6. 사원1: 아직이요 A처리중입니다.
7. 사원1: 팀장님 A 모두 완료했습니다.
8. 팀장: 수고했어요. 사원2시 업무 B좀 해주세요.
9. 사원2: 네 알겠습니다.(B를 처리중)
10. 팀장: 다음 업무 C를 하려면 B가 완료되야 하는데.. 사원2씨 다했어요?
Async + Blocking 조합은 다른 작업이 진행되는 동안 자신의 작업을 멈추고 기다리는 (Blocking), 다른 작업의 결과를 바로 처리하지 않아 순서대로 작업을 수행하지 않는 (Async) 방식이다. 실무에서 잘 맞추하기 쉽지 않아 다룰 일이 거의 없다.