핵심 요약
- 러스트 비동기 처리의 `Future::poll`은 `Pending`과 `Ready` 두 가지 상태만 지원해, 한 번 완료된 퓨처를 다시 호출하면 패닉이 발생하는 구조적 문제가 있습니다.
- 개발자들은 `MaybeDone`이나 `Fuse` 같은 래퍼로 우회해 왔으나, 규격 왜곡과 무한 대기 버그 위험이 상존합니다.
- 세 번째 상태인 `Done`을 추가하는 것이 정석적인 해결책이지만, 하위 호환성 문제로 표준 라이브러리 수정이 쉽지 않은 상황입니다.
요약 러스트(Rust) 언어의 비동기 처리 핵심 요소인 Future 트레이트의 근본적인 한계와 개선안을 다룬 기술 분석 글입니다.
현재 러스트 표준 라이브러리에서 `Future::poll` 메서드는 진행 상태를 `Poll::Pending`(준비 중)과 `Poll::Ready(T)`(완료 및 값 반환) 두 가지 열거형으로만 반환합니다. 문제는 퓨처가 이미 `Ready`를 반환해 값을 뱉어낸 뒤 다시 `poll`을 호출했을 때의 동작입니다. 표준 라이브러리 문서에 따르면 완료된 퓨처를 다시 호출할 경우 패닉(panic)이 발생하거나 무한 대기하는 등 예측할 수 없는 문제가 생길 수 있다고 규정되어 있으며, 실제 대부분의 비동기 블록은 패닉을 일으킵니다.
개발자들은 이를 우회하기 위해 `MaybeDone`이나 `Fuse` 같은 별도의 래퍼(wrapper)를 만들어 완료 여부를 추적해 왔습니다. 하지만 `Fuse`의 경우 완료 후 `Poll::Pending`을 계속 반환하는 꼼수를 쓰는데, 이는 태스크를 깨워야 한다는 `Pending`의 본래 규격과 충돌해 무한 대기 버그를 유발할 위험이 있습니다.
저자는 가장 이상적인 해결책으로 `Poll` 열거형에 세 번째 상태인 `Done`을 추가하는 방안(`Poll::Ready(T)`, `Poll::Pending`, `Poll::Done`)을 제시합니다. 이렇게 하면 퓨처가 완료된 이후에도 호출자에게 안전하게 완료 상태를 알릴 수 있어 복잡한 래퍼 없이 동시성 처리를 깔끔하게 구현할 수 있습니다. 또한 비동기 런타임이 무조건 패닉 처리 코드를 주입할 필요가 없어져 코드 크기가 줄어들고 임베디드 환경에도 큰 이점을 줄 수 있지만, 안타깝게도 현재 표준의 `Poll`이 `#[non_exhaustive]`로 선언되어 있지 않아 하위 호환성 문제로 즉시 수정하기는 어려운 실정입니다.
Sponsored · 광고