동기와 비동기, 블로킹과 논블로킹을 나누어 이해하기

페이지 정보

profile_image
작성자 관리자
댓글 0건 조회 57회 작성일 26-09-15 11:50

본문

동기와 비동기, 블로킹과 논블로킹은 모두 기다림과 관련되어 보여 헷갈리기 쉽습니다. 하지만 무엇을 기다리는지와 어느 실행 흐름이 멈추는지를 나누면 코드를 더 정확히 읽을 수 있습니다.

여기서는 호출 결과를 받는 방식과 실행 자원의 대기를 구분하고 Python asyncio를 구체적인 예로 살펴봅니다.

동기와 비동기, 블로킹과 논블로킹을 나누어 이해하기 관련 설명용 삽화

AI 생성 삽화 · 동기와 비동기, 블로킹과 논블로킹을 나누어 이해하기 주제를 설명하는 이미지입니다.

핵심 정리
비동기는 완료를 나중에 다루는 흐름이고, 논블로킹은 해당 호출이 기다리며 실행 흐름을 붙잡지 않는 성질로 이해할 수 있습니다. async나 await라는 문법만으로 병렬 실행과 성능 향상이 보장되지는 않습니다.


1. 먼저 설명의 기준이 되는 호출을 정합니다

동기와 비동기라는 용어는 API와 문맥에 따라 강조점이 달라집니다. 함수 하나의 반환을 설명하는지, 외부 작업 완료 통지를 설명하는지부터 정해야 합니다.

이 글에서는 요청한 작업의 완료를 호출 흐름에서 직접 다루는지, 나중에 결과를 받아 처리하는지를 구분하는 데 사용합니다. 블로킹은 관심 있는 실행 흐름이 호출 안에서 대기하는지를 보는 관점입니다.

같은 프로그램도 상위 API와 내부 구현을 각각 보면 설명이 달라질 수 있습니다. 비동기 인터페이스 뒤에서 별도 작업 스레드가 블로킹 호출을 수행하는 구성도 생각할 수 있습니다.

따라서 동기라는 단어를 보자마자 프로그램 전체가 멈춘다고 해석하면 범위가 너무 넓습니다. 어떤 함수와 어떤 스레드를 기준으로 말하는지 문장에 붙이면 서로 다른 층의 개념을 섞는 실수를 줄일 수 있습니다.


2. 결과를 기다리는 일과 스레드를 붙잡는 일을 나눕니다

어떤 요청의 결과가 필요하다면 논리적으로 그 결과를 기다리는 단계는 여전히 존재합니다. 비동기 코드라고 기다림이 사라지는 것은 아닙니다.

차이는 기다리는 동안 같은 실행 자원이 다른 준비된 일을 처리할 수 있게 구성했는지에 있습니다. Python asyncio의 공식 개발 문서는 이벤트 루프가 한 스레드에서 작업을 실행하며, 그 스레드에서 한 작업이 실행 중이면 다른 작업은 동시에 실행되지 않는다고 설명합니다.

대기가 가능한 지점에서 실행을 넘겨야 다른 작업이 진행할 기회가 생깁니다. 이 설명에서 작업의 중단과 운영체제 스레드 전체의 대기는 구분해야 합니다.

사용자가 보는 한 요청은 아직 끝나지 않았더라도 이벤트 루프는 다른 요청을 처리할 수 있습니다. 성능을 볼 때도 개별 요청 시간과 여러 요청을 함께 처리하는 정도를 별도로 관찰하는 이유입니다.


3. await를 두 번 쓰면 자동으로 겹치지는 않습니다

Python 공식 코루틴 문서는 코루틴을 차례로 await하는 예와 Task로 등록해 함께 진행하는 예를 구분합니다. 첫 작업을 await한 뒤 다음 작업을 시작하면 코드의 의존 순서는 그대로입니다.

서로 독립적인 작업을 겹쳐 진행하려면 실제로 둘을 스케줄하는 구성이 필요합니다. 이때 await라는 글자의 개수보다 작업을 언제 시작했는지를 보는 편이 정확합니다.

가상으로 프로필 조회와 공지 조회가 서로 독립적이라고 생각해 볼 수 있습니다. 프로필 결과를 받은 뒤에 공지 조회를 시작하는 흐름과 두 조회를 먼저 시작한 뒤 결과를 모으는 흐름은 다릅니다.

반대로 두 번째 조회에 첫 번째 결과의 식별자가 필요하다면 순서를 유지해야 합니다. 동시에 실행할 수 있는지를 판단할 때는 문법을 바꾸기 전에 데이터 의존 관계부터 적어 보는 것이 도움이 됩니다.


4. 긴 계산을 async 안에 넣어도 계산은 남습니다

async 함수 안에서 오래 걸리는 일반 계산을 수행한다고 그 계산이 자동으로 나누어 실행되지는 않습니다. Python 개발 문서는 이벤트 루프에서 직접 실행한 CPU 중심 작업이 다른 작업과 입출력 처리를 지연시킬 수 있다고 설명합니다.

별도 실행 자원으로 분리하는 방법을 검토할 수 있지만 어떤 방식이 적절한지는 작업과 실행 환경에 따라 달라집니다. 초보 단계에서는 무조건 스레드를 추가하는 처방보다 대기와 계산을 먼저 구분하는 편이 좋습니다.

외부 응답을 기다리는 시간이 긴지, 받은 데이터를 계산하는 시간이 긴지 관찰합니다. 한 요청의 로그에서 요청 시작과 응답 수신, 후처리 완료를 나누어 보면 질문이 구체적입니다.

비동기 라이브러리를 사용했다는 사실만으로 전체 경로가 논블로킹이라고 결론 내리지 않고 중간에 호출한 함수의 동작도 확인합니다.


5. 가상 시간표로 의존 관계를 설명해 봅니다

여기서는 두 독립적인 외부 조회가 있다고 가정하고 시간표를 직접 그려 볼 수 있습니다. 첫 줄에는 조회 A의 시작과 완료, 둘째 줄에는 조회 B의 시작과 완료를 표시합니다.

B의 시작이 A의 완료 뒤에 있는지, 두 작업의 대기 구간이 겹치는지를 보면 흐름 차이가 드러납니다. 이는 실제 측정 결과나 처리 속도 보장이 아닌 학습용 가상 예시입니다.

네트워크와 서버 상태가 달라지면 완료 순서도 달라질 수 있으므로 그림의 순서를 제품 동작으로 일반화하지 않습니다. 세 번째 줄에 두 결과를 합치는 단계를 넣으면 병합 시점에 무엇이 필요해지는지도 보입니다.

한쪽이 실패하거나 늦을 때 결과를 어떻게 처리할지 질문을 붙여 봅니다. 단순히 빨라진다는 설명보다 어떤 대기를 겹쳤고 어떤 의존 관계는 유지했는지 설명할 수 있어야 합니다.


6. 완료와 실패를 누가 회수하는지 확인합니다

작업을 시작하는 코드만 있고 결과를 받는 주체가 불분명하면 끝났는지 판단하기 어렵습니다. Python 공식 문서는 Task 참조를 유지하고 관련 작업의 완료와 예외를 관리하는 방식을 설명합니다.

애플리케이션에서는 어떤 요청에 속한 작업인지, 언제 결과가 필요하며 실패를 어디에 전달할지를 정해야 합니다. 이를 공부할 때는 성공 경로뿐 아니라 한 작업이 실패하는 경우를 가상으로 적어 볼 수 있습니다.

다른 결과를 버릴지 일부 결과를 보여 줄지에 따라 필요한 제어 흐름이 달라집니다. 요청을 보냈다는 로그를 작업 성공으로 기록하지 않는 것도 같은 원리입니다.

취소 요청을 보낸 시점과 실제 정리가 끝난 시점도 구분해서 이해합니다. 구체적인 취소와 예외 동작은 사용하는 언어와 라이브러리 문서를 확인해야 하며 한 가지 도식으로 모두 설명하려 하지 않습니다.


7. 코드 리뷰에서는 세 가지 질문을 남깁니다

처음 비동기 코드를 읽을 때는 작업이 언제 시작되는지, 어디에서 결과가 필요해지는지, 그 사이 어떤 실행 흐름이 대기하는지 적어 봅니다. 이 세 질문에 답하면 함수 이름에 async가 붙었다는 인상보다 실제 동작에 가까워집니다.

이어서 동시에 실행해도 되는 작업인지와 실패를 확인하는 주체를 살핍니다. 성능 개선을 주장하려면 변경 전후의 조건을 맞춰 측정해야 합니다.

호출 수나 외부 응답 조건이 다른 결과를 비교해 비동기 전환의 효과라고 단정하지 않습니다. 학습 기록에는 개념 설명과 실제 측정 결과를 구분해 남깁니다.

언어나 프레임워크를 바꿀 때도 용어의 정의와 스케줄링 방식을 다시 확인하면 좋습니다. 동기와 비동기의 이름을 외우는 데서 그치지 않고 한 요청이 완료되기까지의 흐름을 설명하는 것이 목표입니다.


8. 자주 묻는 질문

Q1. 비동기 코드는 항상 더 빠른가요?

항상 그렇지는 않습니다. 겹칠 수 있는 대기가 있는지와 작업을 관리하는 비용, 외부 자원 조건에 따라 달라지므로 실제 조건에서 측정해야 합니다.

Q2. await는 프로그램 전체를 멈추나요?

대상 작업의 결과를 기다리는 흐름과 이벤트 루프의 실행은 구분해야 합니다. 사용하는 awaitable의 동작과 주변 코드에 따라 다른 작업이 진행할 수 있는지를 살펴봅니다.

Q3. async 함수 두 개를 호출하면 동시에 실행되나요?

Python에서는 코루틴 객체를 만드는 것만으로 실행이 예약되지 않습니다. 어떻게 await하거나 Task로 스케줄하는지에 따라 실행 흐름이 달라집니다.

Q4. 동시성과 병렬성은 같은 말인가요?

여러 작업을 겹쳐 진행하는 구성과 여러 실행 자원에서 동시에 계산하는 것은 구분해야 합니다. 비동기라는 표현만으로 여러 CPU 코어를 사용한다고 해석하지 않습니다.


참고 자료

댓글목록

등록된 댓글이 없습니다.