1P by neo with xguru 13일전 | ★ favorite | 댓글 3개
  • Go 1.24에서 WebAssembly(Wasm) 관련 기능이 확장됨
  • go:wasmexport 디렉티브가 추가되어 Wasm 모듈 외부에서 Go 함수를 호출할 수 있게 됨
  • WASI를 위한 “reactor” 빌드 모드도 지원되어, 장기간 활성 상태로 코드를 실행할 수 있게 됨
  • 이를 통해 Wasm 환경에서 Go 애플리케이션을 더 유연하게 확장할 수 있는 가능성이 열림

WebAssembly and the WebAssembly System Interface

  • WebAssembly는 웹 브라우저에서 고성능의 저수준 코드를 실행하기 위해 만들어진 이진 포맷임
  • 현재는 브라우저 외부에서도 광범위하게 활용되고, WebAssembly System Interface(WASI)를 통해 시스템 리소스와 상호작용 가능함
  • Go는 1.11 버전에서 js/wasm 포트를 통해 Wasm 컴파일을 지원하기 시작했으며, 1.21 버전에서는 새로운 GOOS=wasip1 포트를 통해 WASI 프리뷰 1 시스템 호출 API를 타겟으로 하는 새로운 포트를 추가

go:wasmexport를 사용한 Go 함수의 Wasm Export

  • Go 1.24에서 새로 추가된 go:wasmexport 디렉티브를 통해, Go 함수를 Wasm 모듈 외부에서 호출할 수 있도록 export로 노출 가능함
  • 예: //go:wasmexport add처럼 선언한 뒤 함수를 작성하면, Wasm 호스트가 해당 함수를 호출할 수 있음
  • 이는 cgo의 export 디렉티브와 유사하지만, 더 간단한 메커니즘으로 구현됨

Building a WASI Reactor

  • WASI “reactor”는 지속적으로 작동하며 이벤트나 요청에 반응할 수 있는 WebAssembly 모듈을 의미함
  • Go 1.24에서는 -buildmode=c-shared 옵션을 사용해 WASI reactor 빌드를 지원함
  • 이 빌드 플래그는 링커에게 _start 함수(명령 모듈의 진입점)를 생성하지 말고, 대신 _initialize 함수를 생성하도록 지시함
    • reactor는 _initialize 함수를 통해 초기화가 진행되고, main 함수 대신 이 함수를 먼저 호출해야 함
  • Wazero 같은 런타임과 함께 사용하면, _initialize 호출 후에 export된 함수를 원하는 만큼 재호출할 수 있음
  • 이 방식은 애플리케이션의 플러그인 혹은 확장 기제로 Wasm을 활용하는 환경에서 유용함

호스트와 클라이언트 간의 풍부한 타입 지원

  • Go 1.24에서는 go:wasmimport로 호출되는 함수의 매개변수/반환형에 대해 제약이 완화됨
  • 예를 들어, bool, string, int32 포인터, 구조체 포인터 등을 전달할 수 있음
    • 다만 64비트와 32비트 환경 차이 등으로 여전히 제한이 존재함
  • 이는 Go Wasm 애플리케이션을 보다 자연스럽고 편리하게 작성할 수 있도록 하며, 불필요한 타입 변환을 제거

제한 사항

  • Wasm은 병렬 처리가 없는 단일 스레드 아키텍처
  • go:wasmexport 함수는 새로운 고루틴을 생성할 수 있지만, 백그라운드 고루틴을 생성하는 함수는 go:wasmexport 함수가 반환된 후 Go 기반 Wasm 모듈로 다시 호출될 때까지 실행을 계속하지 않음
  • 일부 타입 제한이 완화되었지만, 여전히 go:wasmimport 및 go:wasmexport 함수와 함께 사용할 수 있는 타입에는 제한이 있음
    • 포인터를 포함한 복합 타입 전달에는 아직 제약 사항이 존재

결론

  • Go 1.24의 WASI reactor 빌드 및 go:wasmexport 기능 추가는 Go의 Wasm 생태계를 크게 확장시키는 개선사항임
  • 이를 통해 개발자가 더 다양한 Go 기반 Wasm 애플리케이션을 만들 수 있도록 하여 Wasm 생태계에서 Go의 새로운 가능성을 열어줌

Wasm/gc가 광범위하게 도입되기 전에는 gc가 없는 언어로 wasm 타켓 개발하는게 좋을 것 같아요

Go 1.24 릴리즈 에서는 간단히 설명하는데, 훨씬 중요한 업데이트네요.

Hacker News 의견
  • Go로 생성된 WASM 바이너리가 매우 큰 문제점이 있음. TinyGo는 이를 극복하지만 컴파일 속도가 느리고 라이브러리 선택에 주의가 필요함. 둘 다 극복하려면 많은 인내심이 필요함

    • Cloudflare workers에서 Go WASM을 시도하려면 바이너리 크기 때문에 구독이 필요함
    • 마지막 시도에서는 hello-world는 실행 가능했지만, 더 복잡한 것은 크기 제한을 초과했음
    • 안타까운 상황임
  • 놀라운 점임. 기억해야 할 사항:

    • Go의 웹어셈블리 작업은 Go 팀이 아닌 자원봉사자들에 의해 설계되고 구현되었음. 따라서 일정은 자원봉사자의 가용성에 따라 달라짐
  • Go 1.24 이전에도 Go 함수를 JS로 내보내는 것이 가능하지 않았는지 기억이 잘 나지 않음. 이전에 JS에서 내보낸 Go 함수를 문제없이 호출할 수 있었던 것으로 기억함

    • 새로운 WASI 기능이 이전에 비해 어떻게 개선되었는지 설명해주면 도움이 될 것임 (FFI를 통해 더 많은 유형을 지원하는 것 외에)
    • 두 번째 질문: 포인터를 정수로 캐스팅하여 문자열 및 복잡한 유형을 WASM 모듈의 인스턴스 메모리에서 추출할 수 있었음. Go에서 내 유형의 이진 표현이 안정적임이 보장된다면, goos=wasip1을 사용할 때 생성된 WASM 모듈에 포인터를 전달하는 이 방법이 여전히 유효한지 궁금함
  • 메인 패키지에서 대문자로 시작하는 모든 함수를 내보내는 것이 더 "Go"스러웠을 것 같음. 내보내기는 언어에서 일반적으로 작동하므로 소문자로 시작하는 것을 명시적으로 이름 지정할 때만 컴파일러 지시문을 사용하는 것이 좋음

    • 이는 기존 cgo 내보내기 방식과 동일함. 이전의 예시를 따르는 것임. 사용성은 여전히 언어 외부에 있음
  • WASM 컴포넌트 모델과의 작업에 대한 언급이 없음

  • Go와 WASM의 가비지 컬렉션은 어떻게 작동하는지 궁금함

  • 강력한 타입과 뛰어난 WASM 지원을 갖춘 저수준 언어가 있었으면 좋겠음

  • 호스트 프로그램에서 실행 중인 WASM 모듈을 어떻게 디버그하는지 궁금함

  • 더 많은 WASM 기능에 대한 열망이 젊은 생태계를 돌이킬 수 없게 해칠까 걱정됨. Go가 WASM에 추가한 대부분의 기능은 컴포넌트 모델 제안이 이미 병합되었다면 네이티브로 수행할 수 있었음

    • 표준은 천천히 발전하고 있으며 채택이 증가함에 따라 WASI와 같은 비표준 기능을 영원히 지원해야 할 위험이 있음