백프레셔
백프레셔(backpressure)는 소비자가 처리할 수 있는 양에 맞춰, 생산자가 다음 데이터를 내보내는 속도나 양을 조절하도록 만드는 흐름 제어다. 다운로드한 파일을 처리하는 쪽보다 읽어들이는 쪽이 빠르면 대기열이 계속 커질 수 있는데, 대기열이 찼을 때 생산자도 기다리게 하면 적체가 무한히 늘어나는 것을 막을 수 있다.
여기서는 한 프로세스의 비동기 대기열로 원리를 살펴본다. asyncio.Queue(maxsize=2)가 찼을 때 await put()은 항목이 빠질 때까지 해당 생산자 코루틴을 기다리게 한다. 그동안 이벤트 루프는 다른 작업을 실행할 수 있다. Python Queue 문서

핵심은 produce가 각 put의 완료를 기다린다는 점이다. put 작업을 끝없이 별도 Task로 만들어 두면 대기열 밖에서 기다리는 작업 수가 다시 늘어난다.
꽉 찬 대기열 앞에서 기다리는 생산자
import asyncio
async def produce(queue):
peak = 0
for item in range(6):
await queue.put(item)
peak = max(peak, queue.qsize())
await queue.put(None)
return peak
async def consume(queue):
values = []
while True:
item = await queue.get()
try:
if item is None:
return values
await asyncio.sleep(0.01)
values.append(item)
finally:
queue.task_done()
async def main():
queue = asyncio.Queue(maxsize=2)
async with asyncio.TaskGroup() as group:
producer = group.create_task(produce(queue))
consumer = group.create_task(consume(queue))
await producer
await queue.join()
assert consumer.result() == list(range(6))
assert producer.result() <= 2
print(consumer.result())
if __name__ == "__main__":
asyncio.run(main())Python 3.11 이상에서 실행한다. 생산자가 넣는 여섯 값은 0부터 5이고, None은 입력 값으로 사용하지 않는 종료 표지다. 소비자는 표지를 포함해 get으로 꺼낸 항목마다 task_done을 호출한다. 생산자가 마지막 표지를 넣은 뒤 join으로 모든 항목의 완료를 확인하고, TaskGroup을 나가며 작업 종료도 기다린다.
소비자가 CancelledError를 제외한 일반 예외로 실패하면 TaskGroup이 생산자도 취소하므로, 꽉 찬 대기열 앞에서 계속 기다리는 작업을 남기지 않는다. 소비자 작업 하나만 따로 취소하면 이 실패 전파 규칙이 적용되지 않아 생산자가 계속 기다릴 수 있다. 요청을 중단할 때 두 작업을 함께 끝내려면 부모 작업을 취소하는 등 소유 범위 전체의 종료를 연결해야 한다. TaskGroup의 예외·취소 규칙
task_done은 이 예제의 대기열 회계를 맞추며, 실패한 업무가 성공했다는 뜻으로 해석하지 않는다. 실패는 작업의 예외로 전달된다.
비차단 흐름 제어를 설명하는 원문

Reactive Streams 공식 소개의 첫 문장 부분을 2026년 10월 28일 캡처했다. non-blocking back pressure는 받는 쪽을 무제한 버퍼에 떠넘기지 않으면서 비동기 흐름을 유지하려는 목표와 연결된다. 원문, 공식 명세와 MIT-0 이용 조건.
Reactive Streams의 Publisher·Subscriber·Subscription은 소비자의 요청량을 신호로 전달하는 프로토콜을 정의한다. 위 Queue 예제는 같은 문제를 제한된 버퍼와 기다림으로 보여주며, 그 명세의 인터페이스나 적합성 검사를 구현한 것은 아니다. 명세의 Publisher 규칙 1.1
무엇의 개수를 제한하는가
장치 | 직접 다루는 대상 | 살펴볼 예 |
|---|---|---|
레이트 리미터 | 일정 시간에 허용할 요청량 | 초당 접수 요청 수 |
벌크헤드·동시 실행 상한 | 동시에 자원을 사용하는 작업 수 | 외부 API 호출 칸 |
백프레셔 | 생산자와 소비자 사이의 흐름 | 버퍼가 차면 다음 생산을 기다림 |
- 장치
레이트 리미터
- 직접 다루는 대상
일정 시간에 허용할 요청량
- 살펴볼 예
초당 접수 요청 수
- 장치
벌크헤드·동시 실행 상한
- 직접 다루는 대상
동시에 자원을 사용하는 작업 수
- 살펴볼 예
외부 API 호출 칸
- 장치
백프레셔
- 직접 다루는 대상
생산자와 소비자 사이의 흐름
- 살펴볼 예
버퍼가 차면 다음 생산을 기다림
세 장치는 함께 사용할 수 있다. 대기열 길이가 2여도 소비자가 이미 꺼내 처리 중인 값과 생산자가 다음에 넣으려는 값은 별도로 존재한다. 항목 크기는 서로 다를 수 있으므로, maxsize=2가 제한하는 항목 개수와 프로세스 전체 메모리의 바이트 상한을 구별해야 한다.
생산자를 멈출 수 없는 입력에서는 버리기·최신 값으로 합치기·디스크에 저장하기·접수 거절 같은 정책을 정해야 한다. 대기열 상한만 추가하고 누락된 항목을 성공으로 알리면 업무 계약이 달라진다. 이 예제는 모든 입력 값을 순서대로 처리하는 대기 정책을 사용한다.