제일 흔한 async 실수는 스레드가 더 단순할 때 async 로 손 뻗는 것 — 또는 반대. 이 레슨은 결정 프레임워크야: 언제 async, 언제 스레드, 어떻게 구분하나.
핵심 구분
I/O 바운드 일 (네트워크, 디스크, 타이머 대기) 은 async 에 맞아: 태스크가 시간 대부분을 기다려서, 한 스레드가 각 await 에서 전환해 수천 개를 다뤄. CPU 바운드 일 (수 계산, 파싱, 압축) 은 스레드 에 맞아: 양보할 대기가 없으니, 코어 간 진짜 병렬을 원해.
함정: async 안 블로킹
async 태스크 안의 CPU 무거운 또는 블로킹 연산은 footgun 이야: 양보를 안 해서, 그 스레드의 다른 모든 태스크를 굶겨. async 맥락에서 블로킹 일을 꼭 해야 하면 tokio::task::spawn_blocking 한테 넘겨, 전용 스레드 풀에서 돌려 async 태스크가 계속 흐르게. 두 모델을 부주의하게 섞는 게 1위 async 성능 버그야.
모델을 워크로드에 맞추고, async 실행기를 블록하지 마. I/O 바운드 고동시성 -> async. CPU 바운드 병렬 -> 스레드. async 안 블로킹 일 ->
spawn_blocking. 잘못된 짝은 크래시 안 해 — 처리량을 조용히 파괴해, 크래시보다 디버깅 어려워.둘 다 쓸 수 있어
진짜 시스템은 섞어: CPU 무거운 이미지 리사이즈를 spawn_blocking 이나 스레드 풀로 떼어내는 async 웹 서버 (tokio). 모델은 라이벌이 아니야 — 다른 모양의 일을 위한 도구고, 성숙한 Rust 서비스는 각각 맞는 데 써. 어느 게 어느 건지 아는 게 문법만이 아니라 동시성을 진짜 이해하는 사람의 표식이야.