본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 6장: Go, Python, 기타 언어에서 Wasm
2026년 4월 1일·프로그래밍·

6장: Go, Python, 기타 언어에서 Wasm

TinyGo, Python(componentize-py), C/C++(Emscripten), AssemblyScript, .NET Blazor 등 다양한 언어의 Wasm 지원 현황과 제약 사항, 언어 선택 가이드를 다룹니다.

14분689자10개 섹션
webassemblyrust
공유
webassembly6 / 10
12345678910
이전5장: Rust에서 Wasm 빌드다음7장: 브라우저 고성능 앱 — Wasm의 원래 영역

학습 목표

  • Go(TinyGo)에서 Wasm 컴포넌트를 빌드하는 방법을 익힙니다
  • Python의 Wasm 지원 현황과 componentize-py 사용법을 파악합니다
  • C/C++, AssemblyScript, .NET 등 기타 언어의 Wasm 생태계를 이해합니다
  • 프로젝트 요구사항에 따른 언어 선택 기준을 수립합니다

언어별 Wasm 지원 전체 그림

WebAssembly의 핵심 약속 중 하나는 언어 독립성입니다. 하지만 현실에서 모든 언어의 Wasm 지원 수준이 동일한 것은 아닙니다. 가비지 컬렉터 유무, 런타임 크기, 도구 체인 성숙도에 따라 큰 차이가 존재합니다.

Go와 TinyGo

표준 Go 컴파일러

Go 1.21부터 GOOS=wasip1을 지원합니다. 하지만 표준 Go 컴파일러로 생성되는 Wasm 바이너리는 크기가 상당히 큽니다. Go 런타임(가비지 컬렉터, 고루틴 스케줄러 등)이 통째로 포함되기 때문입니다.

go-wasm-build.sh
bash
# 표준 Go 컴파일러 (WASI Preview 1)
GOOS=wasip1 GOARCH=wasm go build -o app.wasm main.go
 
# 결과: 약 5~15MB (런타임 포함)

TinyGo — Go의 Wasm 최적화 컴파일러

TinyGo는 마이크로컨트롤러와 WebAssembly를 타겟으로 하는 대안 Go 컴파일러입니다. LLVM 기반으로, 표준 Go 컴파일러 대비 훨씬 작은 바이너리를 생성합니다.

main.go
go
package main
 
import (
    "fmt"
    "net/http"
    
    spinhttp "github.com/fermyon/spin-go-sdk/http"
)
 
func init() {
    spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        
        name := r.URL.Query().Get("name")
        if name == "" {
            name = "World"
        }
        
        fmt.Fprintf(w, `{"message":"Hello, %s!"}`, name)
    })
}
 
func main() {}
tinygo-build.sh
bash
# TinyGo로 WASI Preview 2 빌드
tinygo build -target=wasip2 -o app.wasm main.go
 
# 결과: 약 200KB ~ 1MB (표준 Go 대비 1/10 이하)
Warning

TinyGo는 표준 Go 라이브러리의 모든 패키지를 지원하지 않습니다. reflect, net/http(서버 측), database/sql 등 일부 패키지는 사용할 수 없거나 제한적으로만 동작합니다. 프로젝트 시작 전에 TinyGo의 패키지 호환성 문서를 확인해야 합니다.

Go vs TinyGo 비교

항목표준 GoTinyGo
바이너리 크기5~15 MB200KB~1 MB
GC전체 Go GC보수적 GC (간소화)
고루틴완전 지원제한적 지원
표준 라이브러리거의 전부부분적
컴파일러 백엔드Go SSALLVM
컴포넌트 모델미지원지원 (wit-bindgen-go)

Python

Python은 GC 기반 인터프리터 언어이므로, Wasm으로 변환하는 데 근본적인 도전이 있습니다. CPython 인터프리터 전체를 Wasm으로 컴파일해야 하기 때문입니다.

componentize-py

componentize-py는 Python 코드를 Wasm 컴포넌트로 변환하는 도구입니다. CPython 인터프리터를 Wasm으로 임베딩하고, WIT 바인딩을 자동 생성합니다.

app.py
python
import json
from typing import Optional
 
# WIT에서 생성된 바인딩
from bindings.exports.example.api import handler
 
class Handler(handler.Handler):
    def handle_request(self, method: str, path: str, body: Optional[bytes]) -> handler.Response:
        if method == "GET" and path == "/api/status":
            return handler.Response(
                status=200,
                headers=[("content-type", "application/json")],
                body=json.dumps({
                    "status": "ok",
                    "language": "Python",
                    "runtime": "componentize-py"
                }).encode()
            )
        
        return handler.Response(
            status=404,
            headers=[("content-type", "application/json")],
            body=json.dumps({"error": "Not Found"}).encode()
        )
python-build.sh
bash
# componentize-py 설치
pip install componentize-py
 
# Wasm 컴포넌트로 빌드
componentize-py \
  -d wit/world.wit \
  -w api-handler \
  componentize app \
  -o app.wasm
 
# 결과: 약 10~20MB (CPython 인터프리터 포함)
Info

Python Wasm의 바이너리 크기는 10~20MB로 상당히 큽니다. CPython 인터프리터와 필수 표준 라이브러리가 포함되기 때문입니다. 엣지 환경에서는 이 크기가 부담이 될 수 있지만, 서버사이드에서는 콜드 스타트 시간이 여전히 기존 Python 런타임보다 빠릅니다.

PyO3와 Rust-Python 하이브리드

성능이 중요한 부분만 Rust로 작성하고, Python에서 호출하는 하이브리드 접근도 가능합니다.

src/lib.rs
rust
use pyo3::prelude::*;
 
#[pyfunction]
fn process_data(data: Vec<f64>) -> PyResult<Vec<f64>> {
    // 성능 집약적 로직은 Rust로
    Ok(data.iter().map(|x| x * x + 2.0 * x + 1.0).collect())
}
 
#[pymodule]
fn rust_core(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(process_data, m)?)?;
    Ok(())
}

C/C++ — Emscripten

Emscripten은 C/C++ 코드를 WebAssembly로 컴파일하는 가장 오래되고 성숙한 도구 체인입니다. LLVM 기반으로, POSIX API의 상당 부분을 브라우저 환경에서 에뮬레이션합니다.

image_filter.c
c
#include <emscripten.h>
#include <stdint.h>
#include <stdlib.h>
 
// JavaScript에서 호출할 수 있도록 export
EMSCRIPTEN_KEEPALIVE
void apply_blur(uint8_t* pixels, int width, int height, int radius) {
    // 간단한 박스 블러 구현
    uint8_t* temp = (uint8_t*)malloc(width * height * 4);
    
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int r = 0, g = 0, b = 0, count = 0;
            
            for (int dy = -radius; dy <= radius; dy++) {
                for (int dx = -radius; dx <= radius; dx++) {
                    int nx = x + dx, ny = y + dy;
                    if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
                        int idx = (ny * width + nx) * 4;
                        r += pixels[idx];
                        g += pixels[idx + 1];
                        b += pixels[idx + 2];
                        count++;
                    }
                }
            }
            
            int idx = (y * width + x) * 4;
            temp[idx] = r / count;
            temp[idx + 1] = g / count;
            temp[idx + 2] = b / count;
            temp[idx + 3] = pixels[idx + 3]; // alpha
        }
    }
    
    // 결과 복사
    for (int i = 0; i < width * height * 4; i++) {
        pixels[i] = temp[i];
    }
    
    free(temp);
}
emscripten-build.sh
bash
# Emscripten으로 빌드
emcc image_filter.c \
  -O3 \
  -s EXPORTED_FUNCTIONS='["_apply_blur","_malloc","_free"]' \
  -s EXPORTED_RUNTIME_METHODS='["ccall","cwrap"]' \
  -o image_filter.js
 
# 생성 파일: image_filter.js + image_filter.wasm

Emscripten의 강점은 기존 C/C++ 프로젝트를 최소한의 수정으로 Wasm으로 포팅할 수 있다는 점입니다. FFmpeg, SQLite, OpenCV 등 주요 라이브러리들이 이미 Emscripten을 통해 Wasm으로 빌드되고 있습니다.

AssemblyScript

AssemblyScript는 TypeScript와 유사한 문법으로 WebAssembly를 직접 작성할 수 있는 언어입니다. JavaScript/TypeScript 개발자에게 가장 낮은 진입 장벽을 제공합니다.

assembly/index.ts
typescript
// AssemblyScript — TypeScript와 유사하지만
// Wasm 타입에 직접 매핑됩니다
 
export function fibonacci(n: i32): i64 {
  if (n <= 1) return n as i64;
  
  let a: i64 = 0;
  let b: i64 = 1;
  
  for (let i: i32 = 2; i <= n; i++) {
    const temp = a + b;
    a = b;
    b = temp;
  }
  
  return b;
}
 
// 문자열 처리
export function greet(name: string): string {
  return "Hello, " + name + "!";
}
assemblyscript-build.sh
bash
# 설치 및 빌드
npm install assemblyscript
npx asc assembly/index.ts -o build/app.wasm --optimize
 
# 결과: 수 KB ~ 수십 KB (매우 작은 바이너리)
Tip

AssemblyScript는 바이너리 크기가 매우 작아서 브라우저 환경에서 특히 유리합니다. 다만 TypeScript와 100% 호환되지는 않으며, nullable 타입, 클로저 등 일부 기능에 제약이 있습니다. "TypeScript처럼 생긴 별도의 언어"로 이해하는 것이 정확합니다.

.NET과 Blazor WebAssembly

Microsoft의 .NET 플랫폼은 Blazor WebAssembly를 통해 C#으로 웹 프론트엔드를 구축할 수 있습니다. .NET 런타임 자체가 Wasm으로 컴파일되어 브라우저에서 실행됩니다.

Pages/Counter.razor
csharp
@page "/counter"
 
<h1>Counter</h1>
 
<p>Current count: @currentCount</p>
 
<button @onclick="IncrementCount">Click me</button>
 
@code {
    private int currentCount = 0;
 
    private void IncrementCount()
    {
        currentCount++;
    }
}

Blazor의 장점은 C# 개발자가 기존 지식과 라이브러리를 그대로 활용할 수 있다는 점입니다. 하지만 .NET 런타임을 포함한 초기 로딩 크기가 5~10MB에 달하므로, 로딩 최적화가 필수적입니다.

언어 선택 가이드

프로젝트 요구사항에 따라 적합한 언어가 달라집니다.

요구사항추천 언어이유
최소 바이너리 크기Rust, AssemblyScriptGC 없음, 작은 런타임
최고 성능Rust, C/C++제로 오버헤드 추상화, LLVM 최적화
기존 C/C++ 코드 포팅C/C++ (Emscripten)최소 수정으로 마이그레이션
JavaScript 팀AssemblyScriptTypeScript와 유사한 문법
빠른 프로토타이핑Pythoncomponentize-py로 간편 빌드
풀스택 C#.NET (Blazor)프론트/백엔드 언어 통일
서버사이드 + Go 팀TinyGoGo 문법, 작은 바이너리
컴포넌트 모델 필수Rust, TinyGo, Python가장 성숙한 도구 지원
Info

언어 선택에서 가장 중요한 요소는 팀의 기존 역량입니다. Rust가 기술적으로 최적이더라도, Go 전문 팀이라면 TinyGo가 더 현실적인 선택일 수 있습니다. Wasm의 컴포넌트 모델을 활용하면, 핵심 모듈은 Rust로, 비즈니스 로직은 팀에 익숙한 언어로 작성하는 하이브리드 접근도 가능합니다.

정리

이번 장에서는 Rust 외 다양한 언어의 Wasm 지원 현황을 살펴보았습니다.

  • TinyGo는 Go 문법으로 작은 Wasm 바이너리를 생성하지만, 표준 라이브러리 호환성에 제약이 있습니다
  • Python은 componentize-py로 Wasm 컴포넌트를 빌드할 수 있으나, 바이너리 크기가 큽니다
  • Emscripten은 기존 C/C++ 코드를 Wasm으로 포팅하는 가장 성숙한 경로입니다
  • AssemblyScript는 TypeScript와 유사한 문법으로 매우 작은 바이너리를 생성합니다
  • 언어 선택은 바이너리 크기, 성능, 팀 역량, 생태계를 종합적으로 고려해야 합니다

다음 장 미리보기

7장에서는 WebAssembly의 원래 영역인 브라우저로 돌아갑니다. JavaScript와 Wasm의 상호 호출, Web API 연동, 이미지/비디오 처리, AI 추론 등 브라우저에서 고성능 애플리케이션을 구축하는 방법을 다룹니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#webassembly#rust

관련 글

프로그래밍

7장: 브라우저 고성능 앱 — Wasm의 원래 영역

JavaScript와 Wasm의 상호 호출, Web API 연동, 이미지/비디오 처리, AI 추론, 게임 엔진 등 브라우저에서 WebAssembly로 고성능 애플리케이션을 구축하는 방법을 다룹니다.

2026년 4월 3일·14분
프로그래밍

5장: Rust에서 Wasm 빌드

Rust에서 WebAssembly를 빌드하는 전체 과정을 다룹니다. wasm-pack, cargo-component, 크기 최적화, WASI 타겟 빌드, 컴포넌트 모델 적용, HTTP 핸들러 실전 예제까지.

2026년 3월 30일·13분
프로그래밍

8장: 서버사이드 Wasm — Spin, Fermyon, SpinKube

Spin 프레임워크의 아키텍처, Fermyon Cloud와 Akamai 통합, SpinKube를 활용한 Kubernetes 배포, Docker와 Wasm의 비교를 통해 서버사이드 WebAssembly의 현재를 분석합니다.

2026년 4월 5일·16분
이전 글5장: Rust에서 Wasm 빌드
다음 글7장: 브라우저 고성능 앱 — Wasm의 원래 영역

댓글

목차

약 14분 남음
  • 학습 목표
  • 언어별 Wasm 지원 전체 그림
  • Go와 TinyGo
    • 표준 Go 컴파일러
    • TinyGo — Go의 Wasm 최적화 컴파일러
    • Go vs TinyGo 비교
  • Python
    • componentize-py
    • PyO3와 Rust-Python 하이브리드
  • C/C++ — Emscripten
  • AssemblyScript
  • .NET과 Blazor WebAssembly
  • 언어 선택 가이드
  • 정리
  • 다음 장 미리보기