처리중입니다. 잠시만 기다려주세요.
TTJ 코딩클래스
정규반 단과 자료실 테크 뉴스 코딩 퀴즈
테크 뉴스
Hacker News 2026.04.26 32

async가 약속한 것과 실제로 가져다준 것 — 비동기 10년의 회고

Hacker News 원문 보기
async가 약속한 것과 실제로 가져다준 것 — 비동기 10년의 회고

도입: async/await, 정말 우리 삶을 편하게 만들었나요

2010년대 초중반부터 거의 모든 주류 언어가 async/await 키워드를 받아들였어요. JavaScript, C#, Python, Rust, Kotlin, Swift… 안 받은 언어를 찾기가 더 어려울 정도였죠. 당시 약속은 명확했어요. "콜백 지옥은 끝났다. 동기 코드처럼 쓰지만 비동기로 돌아간다. 성능도 좋고 가독성도 좋다." 그런데 10년쯤 지난 지금, 정말 그 약속은 지켜졌을까요? 최근 한 엔지니어가 쓴 회고 에세이가 이 질문을 정면으로 다루는데, 함께 곱씹어볼 만해요.

약속됐던 것들

async가 등장하기 전, 비동기 코드는 콜백을 중첩하거나 Promise/Future 체인을 길게 이어 붙여야 했어요. then().then().catch() 가 끝없이 이어지던 그 시절을 기억하시는 분도 많을 거예요. async/await의 첫 번째 약속은 "동기 코드처럼 위에서 아래로 읽히게 해주겠다" 였어요. await fetch(url) 한 줄이면 끝나니까요.

두 번째 약속은 성능이었어요. 스레드 하나에 OS 입장에서 수 MB의 스택이 붙는데, async는 "태스크"라는 가벼운 단위로 수만 개 동시 작업을 돌릴 수 있다고 했어요. 웹 서버에서 수십만 동시 연결을 처리하려면 이 길밖에 없다는 논리였죠. 세 번째 약속은 조합 가능성(composability), 즉 비동기 함수들을 마치 레고 블록처럼 자유롭게 합성할 수 있다는 거였어요.

실제로 일어난 일

좋은 소식부터요. 가독성은 정말 좋아졌어요. 콜백 헬은 거의 사라졌고, async function 안에서 try/catch로 에러 처리도 자연스럽게 됩니다. 그건 명백한 진보예요.

그런데 그늘도 짙어요. 첫째, '함수 색깔(function coloring)' 문제가 생겼어요. 이게 뭐냐면, async 함수는 async 함수에서만 깔끔하게 호출할 수 있어서, 코드베이스 한쪽에 async를 도입하는 순간 그 호출 체인 전체가 async로 물들어버리거든요. 동기 함수와 비동기 함수가 마치 다른 색의 페인트처럼 안 섞이는 거예요. 결과적으로 같은 로직을 동기/비동기 두 벌로 유지하는 라이브러리가 늘었어요. Python의 requestsaiohttp처럼요.

둘째, 추상화의 누수가 심해요. await 한 줄이 동기처럼 보이지만, 실제로는 런타임이 태스크를 큐에 넣고 이벤트 루프가 돌아가는 복잡한 메커니즘이 뒤에 깔려 있어요. 그래서 데드락, 캔슬레이션 누수, 백프레셔(backpressure) 같은 문제가 생기면 디버깅이 정말 고통스러워집니다. 스택 트레이스를 봐도 진짜 호출 경로가 안 나오는 경우가 흔하고요.

셋째, 성능 약속도 절반의 진실이에요. CPU 바운드 작업은 async가 도와주지 못하고, I/O 바운드라 해도 스레드 풀과의 차이가 생각보다 크지 않은 워크로드가 많아요. Node.js 같은 단일 이벤트 루프 모델은 한 태스크가 잠깐 블로킹만 해도 전체가 멈춰요.

업계 흐름: 다른 길은 없었나요

async에 대한 회의가 커지면서 대안들이 다시 주목받고 있어요. Go의 고루틴은 사용자 입장에서 그냥 go f() 한 줄이고, 함수에 색깔이 안 묻어요. Java 21의 Virtual Threads(Project Loom)도 같은 철학이에요. 기존 동기 코드를 그대로 쓰면서 OS 스레드보다 훨씬 가볍게 운용한다는 거죠. Erlang/Elixir의 BEAM 모델은 더 일찍 이 답을 가지고 있었고요. 즉, "언어가 색깔을 강요하지 않고, 런타임이 알아서 스케줄링한다"는 방향이 다시 힘을 얻고 있어요.

Rust는 정반대 극단에서 async를 zero-cost 추상화로 밀어붙였는데, 그 대가로 라이프타임과 Pin, Send/Sync 경계가 얽혀 학습 곡선이 가팔라졌어요. 이것도 "async가 정말 모든 언어에 맞는 모델인가"라는 질문을 던지게 만들죠.

한국 개발자에게는

당장 우리 코드를 다 갈아엎으라는 얘기는 아니에요. 다만 도구를 고를 때 "이 워크로드에 진짜 async가 필요한가?"를 한 번 더 묻는 습관이 필요해요. 단순한 백엔드 API라면 Java 21 Virtual Threads나 Go가 훨씬 마음 편한 선택일 수 있고, 동시성이 정말 극단적인 시스템이라면 Rust async의 비용도 정당화돼요. 또 async 코드를 쓸 때는 캔슬레이션, 타임아웃, 백프레셔를 처음부터 설계에 넣으세요. 나중에 끼워 넣으면 정말 아파요.

마무리

한 줄로 정리하면, "async/await는 가독성을 줬지만 복잡성을 그대로 옮겨놨을 뿐이다" 라는 통찰이에요. 여러분의 프로젝트에서 async 도입 후 가장 후회했던 결정은 무엇이었나요? 반대로, async가 아니었으면 안 됐을 멋진 사례도 있었다면 들려주세요.


🔗 출처: Hacker News

이 뉴스가 유용했나요?

이 기술을 직접 배워보세요

파이썬으로 자동화를 시작해보세요

파이썬 기초부터 자동화까지 실전 강의.

파이썬 강의 보기

"비전공 직장인인데 반년 만에 수익 파이프라인을 여러 개 만들었습니다"

실제 수강생 후기
  • 비전공자도 6개월이면 첫 수익
  • 20년 경력 개발자 직강
  • 자동화 프로그램 + 소스코드 제공

매일 AI·개발 뉴스를 받아보세요

주요 테크 뉴스를 매일 아침 이메일로 전해드립니다.

스팸 없이, 언제든 구독 취소 가능합니다.