Hello
📝Async vs Sync in Python
python
async
2025
Async def에 대해 알아보기
async def와 def의 차이는 함수의 실행 방식(동기 vs 비동기)에 있어요.
🧩 기본 개념
| 구분 | def (일반 함수) |
async def (비동기 함수) |
|---|---|---|
| 실행 방식 | 동기(Synchronous) | 비동기(Asynchronous) |
| 반환 값 | 일반적인 값 (예: int, list) |
코루틴 객체 (coroutine) |
| 실행 시점 | 즉시 실행되어 결과를 반환 | 실행되지만 await로 기다려야 실제 결과를 얻음 |
⚙️ 예시 비교
(1) 일반 함수 (def)
def는 호출되면 바로 실행되고 결과를 반환해요.
(2) 비동기 함수 (async def)
<coroutine object greet at 0x7ea4903cb110>
async def로 정의된 함수는 즉시 실행되지 않음- 대신 “코루틴(coroutine)” 객체를 반환
- 실제 실행하려면
await또는asyncio.run()을 써야 함
await로 실행하기
import asyncio # ✅ asyncio: 파이썬의 비동기(Asynchronous) 프로그래밍을 지원하는 표준 모듈
# ============================================================
# ① 코루틴(Coroutine) 정의
# ============================================================
# async def 로 정의된 함수는 일반 함수처럼 즉시 실행되지 않음.
# 호출 시 '코루틴 객체(coroutine object)'를 반환하고,
# 이 객체를 이벤트 루프(event loop)가 스케줄링해서 실제로 실행함.
async def greet():
# 이 함수는 단순히 "Hello" 문자열을 반환하는 비동기 함수
return "Hello"
# ============================================================
# ② 메인 코루틴 (다른 코루틴을 호출하고 관리)
# ============================================================
async def main():
# await 키워드는 '코루틴 실행 결과를 기다린다'는 의미.
# greet()를 호출하면 즉시 실행되는 게 아니라 코루틴 객체를 반환함.
# await greet()는 이벤트 루프에게 "이 코루틴을 실행하고 끝날 때까지 기다려줘"라고 요청함.
result = await greet()
# greet()의 실행이 완료되면, result에는 "Hello"가 저장됨.
print(result) # 콘솔에 "Hello" 출력
# ============================================================
# ③ 이벤트 루프(Event Loop)
# ============================================================
# asyncio.run()은 파이썬 3.7부터 도입된 고수준 API로,
# 내부적으로 다음과 같은 과정을 수행함:
#
# 1️⃣ 새로운 이벤트 루프 생성
# 2️⃣ main() 코루틴을 루프에 등록하고 실행 시작
# 3️⃣ await 구문 등을 통해 다른 코루틴들을 스케줄링하여 실행 순서를 관리
# 4️⃣ 모든 코루틴이 완료되면 루프를 정리하고 종료
#
# 즉, 프로그램 전체의 비동기 작업을 총괄하는 "조정자" 역할을 함.
asyncio.run(main())📌 실행 결과
Hello
이벤트 루프 내부 구성을 나타내면 아래와 같습니다.
flowchart TD
%% =============================
%% asyncio (High-level)
%% =============================
subgraph A["asyncio (고수준 API)"]
A1["asyncio.run(main)"]
A2["루프 생성 및<br>run_until_complete(Task(main))"]
A3["Task<br>코루틴 실행 단위<br>(상태/콜백/스택 보유)"]
A4["Future<br>결과·예외 저장, 콜백 등록 가능"]
A1 --> A2
A2 --> A3
A2 --> A4
end
%% =============================
%% Event Loop 내부 구조
%% =============================
subgraph B["Event Loop (단일 스레드, 협력형 전환)"]
direction LR
B1["Ready Queue"]
B2["Callback Queue"]
B3["실행 단계<br>(한 틱씩 Task 실행)"]
B5["Selector / IO<br>(epoll, kqueue)"]
B6["타이머 힙<br>(지연 콜백, sleep)"]
B1 <-->|"콜백 이동"| B2
B2 -->|"run_ready()"| B3
B5 <-->|"poll(timeout)"| B3
B3 --> B6
end
%% =============================
%% Control Flow
%% =============================
A3 -. "await" .-> B3
B3 -. "I/O 완료·타이머 만료" .-> B1
B1 -->|"Task 재개"| A3
⏱️ 언제 async def를 써야 할까?
비동기는 I/O 작업(입출력)이 오래 걸리는 아래와 같은 상황에서 유용합니다.
- 네트워크 요청 (
HTTP request) - 파일 읽기/쓰기
- 데이터베이스 쿼리
- 대기 시간(
sleep)이 많은 코드
📌 실행 결과
다운로드 시작
다운로드 시작
다운로드 시작
(2초 후)
다운로드 완료
다운로드 완료
다운로드 완료
세 개가 동시에 실행되어 총 2초만 걸려요! 만약
def였다면 순서대로 실행되어 6초가 걸렸을 겁니다.
| 항목 | def |
async def |
|---|---|---|
| 실행 시점 | 즉시 실행 | 코루틴 객체 반환 |
| 반환 값 | 일반 값 | coroutine |
| 결과 받기 | 바로 가능 | await 필요 |
| 주 용도 | CPU 연산 중심 코드 | I/O 중심(대기 많은) 코드 |
| 병렬 처리 | 어렵다 | asyncio.gather() 등으로 쉽게 가능 |
🚀 동기 vs 비동기 실행 데모
import asyncio
import time
# ------------------ 동기 (def) ------------------
def sync_task(name):
print(f"{name} 시작")
time.sleep(2)
print(f"{name} 완료")
def sync_main():
start = time.time()
for i in range(3):
sync_task(f"작업 {i+1}")
print(f"총 소요 시간(동기): {time.time() - start:.2f}초")
# ------------------ 비동기 (async def) ------------------
async def async_task(name):
print(f"{name} 시작")
await asyncio.sleep(2)
print(f"{name} 완료")
async def async_main():
start = time.time()
await asyncio.gather(*[async_task(f"작업 {i+1}") for i in range(3)])
print(f"총 소요 시간(비동기): {time.time() - start:.2f}초")
print("\n=== 동기 실행 ===")
sync_main()
print("\n=== 비동기 실행 ===")
# 이미 실행 중인 루프에서 안전하게 실행 (top-level await)
await async_main()
=== 동기 실행 ===
작업 1 시작
작업 1 완료
작업 2 시작
작업 2 완료
작업 3 시작
작업 3 완료
총 소요 시간(동기): 6.00초
=== 비동기 실행 ===
작업 1 시작
작업 2 시작
작업 3 시작
작업 1 완료
작업 2 완료
작업 3 완료
총 소요 시간(비동기): 2.00초
🔍 결과 해석
- 동기(
def): 1→2→3 순차 실행 → 약 6초 - 비동기(
async def): 3개 동시 실행 → 약 2초
비동기는 대기(I/O) 시간이 많은 작업에서 큰 이점을 제공합니다.