Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

WASI 0.3의 네이티브 비동기

WASI 0.3은 비동기 기능을 가능하게 하는 새로운 정규 ABI 프리미티브를 컴포넌트 모델에 추가합니다. WASI 0.3을 대상으로 하는 컴포넌트는 WIT 파일에서 다음과 같은 새로운 기능을 사용할 수 있습니다.

  • async func
  • stream<T>
  • future<T>

이러한 새로운 타입을 통해 인터페이스는 컴포넌트 경계를 넘어 합성되는 비동기 작업을 표현할 수 있습니다.

마이그레이션 메커니즘(예: WASI 0.2 컴포넌트가 이러한 프리미티브에 어떻게 매핑되는지)에 대해서는 WASI 0.2에서 WASI 0.3으로 마이그레이션하기를 참조하십시오.

인터페이스별 전체 diff를 포함하여 WASI 0.3 릴리스를 더 자세히 살펴보려면 WASI.dev의 WASI 0.3을 참조하십시오.

이 페이지는 컴포넌트 모델 개념 자체에 초점을 맞춥니다.

Note

WASI 0.3은 WASI 0.2를 대체하는 것이 아니라 그 위에 구축됩니다. 런타임은 두 버전을 나란히 호스팅할 수 있으며, 0.3 호스트는 경계에서 0.2 임포트를 폴리필할 수 있으므로, 애플리케이션은 툴체인과 의존성이 0.3 지원을 갖추어 감에 따라 점진적으로 마이그레이션할 수 있습니다.

WASI 0.3이 해결하는 비동기 문제

컴포넌트 모델의 정규 ABI는 타입이 지정된 값이 컴포넌트 경계를 넘는 방식을 정의합니다. WASI 0.3 이전까지 이 어휘 체계에는 일시 중단이나 비동기 완료라는 개념이 없었습니다. 모든 인터페이스 호출은 동기적으로 반환되었으며, 비동기 I/O는 해당 리소스를 획득한 컴포넌트에 범위가 한정된 리소스(준비 상태를 위한 pollable, 바이트 채널을 위한 input-stream 및 output-stream)로 모델링되었습니다.

이러한 방식은 두 당사자 간의 상호 작용에서는 잘 동작하지만, 컴포넌트가 체인으로 합성되면 제대로 동작하지 않습니다. 어떤 컴포넌트가 다른 컴포넌트가 다시 위임하는 작업을 기다리는 경우, 준비 상태 신호는 체인을 거슬러 올라가야 합니다. 준비 상태가 단일 컴포넌트에 범위가 한정된 리소스로 표현되면, 중간 컴포넌트는 오로지 호출자에게 웨이크업을 전달하기 위해 이벤트 루프를 계속 실행할 수밖에 없습니다. 리소스가 런타임이 경계를 넘어 접근할 수 있는 위치에 있지 않으므로 런타임은 도움을 줄 수 없습니다. 이를 샌드위치 문제라고 부르기도 합니다. 이는 단일 홉은 문제없이 기술하지만 그 이상으로는 준비 상태를 전파할 수 없는 비동기 어휘 체계를 가리킵니다.

네이티브 비동기 프리미티브는 이러한 표현력의 격차를 좁히는 데 도움이 됩니다. WIT 수준에서 async func, stream<T>, future<T>를 사용할 수 있게 하는 업데이트된 컴포넌트 ABI 메커니즘을 통해, 스케줄링과 웨이크업 전파는 개별 컴포넌트가 아닌 런타임의 역할이 됩니다.

컴포넌트는 WASI 0.2에서 필요했던 것처럼 준비 상태를 중계하기 위해 자체 이벤트 루프를 계속 실행하지 않고도 퓨처와 스트림을 전달할 수 있습니다.

비동기 함수, 스트림, 퓨처

비동기 함수(async func)

async로 선언된 WIT 함수는 해당 호출이 결과를 생성하기 전에 일시 중단될 수 있음을 런타임에 알립니다. 정규 ABI가 일시 중단과 재개를 처리합니다. 게스트는 pollable을 보지 않으며, 호스트는 폴링 루프를 보지 않습니다.

- handle: func(request: request) -> result<response, error-code>;
+ handle: async func(request: request) -> result<response, error-code>;

WIT에서 생성된 코드는 각 언어의 자연스러운 비동기 관용구를 따릅니다. Rust에서는 async fn, JavaScript에서는 Promise를 반환하는 함수, Python에서는 코루틴이 됩니다.

스트림(stream<T>)

T 값의 시퀀스를 위한, 타입이 지정된 비동기 채널입니다. 중요한 점은 stream<T>가 (WASI 0.2와 달리) 리소스가 아닌 정규 ABI 값이라는 것입니다 – 호출에서 반환되거나, 매개변수로 받아들여지거나, 기반 버퍼의 소유권을 포기하지 않고 한 컴포넌트에서 다른 컴포넌트로 넘겨질 수 있습니다.

또한 동일한 값을 하나 이상의 중간 컴포넌트를 곧바로 통과시켜 전달할 수도 있으며, 이때 해당 컴포넌트들은 웨이크업을 중계할 필요가 없습니다.

read-via-stream: func() -> tuple<stream<u8>, future<result<_, error-code>>>;

퓨처(future<T>)

나중에 사용할 수 있게 될 단일 값에 대한 타입이 지정된 핸들입니다. stream<T>와 마찬가지로 future<T>는 리소스가 아니라 값이므로, 기본 타입과 같은 방식으로 컴포넌트 경계를 넘나듭니다.

future<T>를 반환하는 동기 함수는 블로킹할 수 없다는 점에 유의하십시오. 호출자는 결과가 필요할 때 이를 await할 수 있습니다.

write-via-stream: func(data: stream<u8>) -> future<result<_, error-code>>;

WASI 0.3의 비동기 패턴 살펴보기

스트림과 종료 퓨처

읽기 작업은 데이터 채널과 완료 핸들을 튜플로 묶어 함께 반환합니다(wasi-filesystem의 read-via-stream):

read-via-stream: func() -> tuple<stream<u8>, future<result<_, error-code>>>;

두 부분은 서로 독립적입니다. 호출자는 스트림을 즉시 소비하거나, 일부만 샘플링하거나, 도중에 드롭할 수 있습니다. 어느 경우든 작업이 종료되면 퓨처가 성공 또는 실패 결과를 담아 완료됩니다. 같은 형태가 stdin, 파일 시스템 읽기, TCP 수신, 디렉터리 목록 조회에도 나타납니다.

스트림 매개변수, 퓨처 반환

쓰기 작업은 대칭적인 형태를 사용합니다. 게스트는 데이터를 stream<u8> 매개변수로 제공하고, 호스트는 스트림을 모두 소비하면 완료되는 future를 반환합니다. stdout, stderr, 파일 시스템 쓰기, TCP 송신은 모두 이 형태를 따릅니다(wasi-filesystem의 write-via-stream):

write-via-stream: func(data: stream<u8>) -> future<result<_, error-code>>;

다음 단계

이러한 기본 요소를 실제로 사용하는 엔드 투 엔드 Rust 예제는 Rust로 실행 가능한 컴포넌트 만들기를 참조하십시오. 런타임 지원 및 CLI 플래그에 대해서는 Wasmtime을 참조하십시오. WIT 구문에 대한 자세한 내용은 WIT 레퍼런스를 참조하십시오.


원문 © 2023 The Bytecode Alliance Contributors · WebAssembly Components Documentation · CC BY 4.0
Yeokja 한국어 번역·편집 · Anthropic 사의 claude-sonnet-5 모델을 활용하여 번역되었으며 학습을 모두 비허용한 상태로 작업하였습니다 · 이 번역은 원문을 수정한 문서이며 CC BY 4.0으로 제공합니다.