Chrome 70에서 WebAssembly 스레드를 사용해 볼 수 있음

WebAssembly 스레드 지원은 Chrome 70의 Origin Trial에서 제공되었습니다.

Alex Danilo

WebAssembly (Wasm)를 사용하면 C++ 및 다른 언어로 작성된 코드를 컴파일하여 웹에서 실행할 수 있습니다. 네이티브 애플리케이션의 매우 유용한 기능 중 하나는 동시 컴퓨팅의 프리미티브인 스레드를 사용할 수 있는 기능입니다. 대부분의 C 및 C++ 개발자는 애플리케이션의 스레드 관리를 위한 표준화된 API인 pthreads를 잘 알고 있습니다.

WebAssembly 커뮤니티 그룹은 실제 멀티스레드 애플리케이션을 지원하기 위해 웹에 스레드를 도입하기 위해 노력하고 있습니다. 이 작업의 일환으로 V8은 Origin Trial을 통해 제공되는 WebAssembly 엔진에서 스레드에 필요한 지원을 구현했습니다. 오리진 체험판을 사용하면 개발자가 새 웹 기능이 완전히 표준화되기 전에 이를 실험할 수 있습니다. 이를 통해 새로운 기능을 검증하고 개선하는 데 중요한 역할을 하는 용감한 개발자의 실제 의견을 수집할 수 있습니다.

Chrome 70 출시에서는 WebAssembly용 스레드를 지원하며, 관심 있는 개발자는 스레드를 사용해 보고 의견을 보내주시기 바랍니다.

스레드? 작업자는 어떨까요?

브라우저는 2012년 Chrome 4부터 웹 워커를 통한 동시 실행을 지원해 왔습니다. 실제로 '기본 스레드에서'와 같은 용어를 듣는 것은 정상입니다. 하지만 웹 워커는 변경 가능한 데이터를 서로 공유하지 않고 대신 통신을 위해 메시지 전달을 사용합니다. 실제로 Chrome은 각각에 대해 새 V8 엔진(격리라고 함)을 할당합니다. 격리는 컴파일된 코드나 JavaScript 객체를 공유하지 않으므로 pthreads와 같은 변경 가능한 데이터를 공유할 수 없습니다.

반면 WebAssembly 스레드는 동일한 Wasm 메모리를 공유할 수 있는 스레드입니다. 공유 메모리의 기본 저장소는 작업자 간에 단일 ArrayBuffer의 콘텐츠를 동시에 공유할 수 있게 하는 자바스크립트 프리미티브인 SharedArrayBuffer를 사용합니다. 각 WebAssembly 스레드는 웹 작업자에서 실행되지만 공유된 Wasm 메모리를 사용하면 네이티브 플랫폼에서와 마찬가지로 작동할 수 있습니다. 즉, Wasm 스레드를 사용하는 애플리케이션은 기존 스레드 애플리케이션과 마찬가지로 공유 메모리에 대한 액세스를 관리해야 합니다. C 또는 C++로 작성된 기존 코드 라이브러리가 많이 있으며 pthreads가 Wasm으로 컴파일되어 실제 스레드 모드로 실행되므로 더 많은 코어가 동일한 데이터에서 동시에 작동할 수 있습니다.

간단한 예

다음은 스레드를 사용하는 간단한 'C' 프로그램의 예입니다.

#include <pthread.h>
#include <stdio.h>

// Calculate Fibonacci numbers shared function
int fibonacci(int iterations) {
    int     val = 1;
    int     last = 0;

    if (iterations == 0) {
        return 0;
    }
    for (int i = 1; i < iterations; i++) {
        int     seq;

        seq = val + last;
        last = val;
        val = seq;
    }
    return val;
}
// Start function for the background thread
void *bg_func(void *arg) {
    int     *iter = (void *)arg;

    *iter = fibonacci(*iter);
    return arg;
}
// Foreground thread and main entry point
int main(int argc, char *argv[]) {
    int         fg_val = 54;
    int         bg_val = 42;
    pthread_t   bg_thread;

    // Create the background thread
    if (pthread_create(&bg_thread, NULL, bg_func, &bg_val)) {
        perror("Thread create failed");
        return 1;
    }
    // Calculate on the foreground thread
    fg_val = fibonacci(fg_val);
    // Wait for background thread to finish
    if (pthread_join(bg_thread, NULL)) {
        perror("Thread join failed");
        return 2;
    }
    // Show the result from background and foreground threads
    printf("Fib(42) is %d, Fib(6 * 9) is %d\n", bg_val, fg_val);

    return 0;
}

이 코드는 두 변수 fg_valbg_val를 선언하는 main() 함수로 시작합니다. 이 예시에서 두 스레드 모두에서 호출할 fibonacci()라는 함수도 있습니다. main() 함수는 pthread_create()를 사용하여 백그라운드 스레드를 만듭니다. 이 스레드의 작업은 bg_val 변수의 값에 해당하는 피보나치 수 시퀀스 값을 계산하는 것입니다. 한편 포그라운드 스레드에서 실행되는 main() 함수는 이를 fg_val 변수에 대해 계산합니다. 백그라운드 스레드가 실행을 완료하면 결과가 출력됩니다.

스레드 지원을 위해 컴파일

먼저 emscripten SDK(버전 1.38.11 이상 권장)가 설치되어 있어야 합니다. 브라우저에서 실행되도록 스레드가 사용 설정된 예시 코드를 빌드하려면 emscripten emcc 컴파일러에 몇 가지 추가 플래그를 전달해야 합니다. 명령줄은 다음과 같습니다.

emcc -O2 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -o test.js test.c

명령줄 인수 '-s USE_PTHREADS=1'는 컴파일된 WebAssembly 모듈의 스레딩 지원을 사용 설정하고 인수 '-s PTHREAD_POOL_SIZE=2'는 컴파일러에 스레드 2개 풀을 생성하도록 지시합니다.

프로그램이 실행되면 내부적으로 WebAssembly 모듈을 로드하고, 스레드 풀의 각 스레드에 대해 웹 작업자를 만들고, 각 작업자(이 경우 2개)와 모듈을 공유합니다. 이러한 작업자는 pthread_create() 호출이 실행될 때마다 사용됩니다. 각 작업자는 동일한 메모리로 Wasm 모듈을 인스턴스화하여 협력할 수 있습니다. V8의 최신 7.0 변경사항은 작업자 간에 전달되는 Wasm 모듈의 컴파일된 네이티브 코드를 공유하므로 매우 큰 애플리케이션도 많은 작업자로 확장할 수 있습니다. 스레드 풀 크기가 애플리케이션에 필요한 최대 스레드 수와 동일한지 확인하는 것이 좋습니다. 그러지 않으면 스레드 생성에 실패할 수 있습니다. 동시에 스레드 풀 크기가 너무 크면 메모리만 사용하는 불필요한 웹 워커를 생성하게 됩니다.

DTP 사용해 보기

WebAssembly 모듈을 테스트하는 가장 빠른 방법은 Chrome 70 이상에서 실험용 WebAssembly 스레드 지원을 사용 설정하는 것입니다. 아래와 같이 브라우저에서 URL about://flags로 이동합니다.

Chrome 플래그 페이지

그런 다음 다음과 같이 실험용 WebAssembly 스레드 설정을 찾습니다.

WebAssembly 스레드 설정

아래와 같이 설정을 사용 설정됨으로 변경한 후 브라우저를 다시 시작합니다.

WebAssembly 스레드 설정 사용 설정됨

브라우저가 다시 시작된 후 다음 콘텐츠만 포함된 최소한의 HTML 페이지를 사용하여 스레드된 WebAssembly 모듈을 로드해 볼 수 있습니다.

<!DOCTYPE html>
<html>
  <title>Threads test</title>
  <body>
    <script src="test.js"></script>
  </body>
</html>

이 페이지를 사용하려면 일종의 웹 서버를 실행하고 브라우저에서 로드해야 합니다. 그러면 WebAssembly 모듈이 로드되고 실행됩니다. DevTools를 열면 실행 출력이 표시되고 콘솔에 아래와 같은 출력 이미지가 표시됩니다.

피보나치 프로그램의 콘솔 출력

스레드가 있는 WebAssembly 프로그램이 성공적으로 실행되었습니다. 위에 설명된 단계에 따라 자체 스레드 애플리케이션을 사용해 보시기 바랍니다.

오리진 트라이얼을 사용하여 현장에서 테스트

브라우저에서 실험용 플래그를 사용 설정하여 스레드를 테스트하는 것은 개발 목적으로는 좋지만, 필드에서 애플리케이션을 테스트하려면 출처 체험판을 사용하면 됩니다.

오리진 트라이얼을 사용하면 도메인에 연결된 테스트 토큰을 가져와서 사용자와 함께 실험용 기능을 사용해 볼 수 있습니다. 그런 다음 앱을 배포하고 테스트 중인 기능을 지원할 수 있는 브라우저(이 경우 Chrome 70 이상)에서 작동할 것으로 기대할 수 있습니다. 출처 무료 체험을 실행할 자체 토큰을 가져오려면 여기에 있는 신청 양식을 사용하세요.

위의 간단한 예시는 출처 체험판 토큰을 사용하여 호스팅되었으므로 빌드할 필요 없이 직접 사용해 볼 수 있습니다.

병렬로 실행되는 4개의 스레드가 ASCII 아트에 어떤 영향을 미치는지 확인하려면 이 데모도 살펴보세요.

의견 보내기

WebAssembly 스레드는 애플리케이션을 웹에 포팅하는 데 매우 유용한 새로운 프리미티브입니다. 이제 WebAssembly 환경에서 pthreads 지원이 필요한 C 및 C++ 애플리케이션과 라이브러리를 실행할 수 있습니다.

이 기능을 사용해 본 개발자의 의견을 기다리고 있습니다. 표준화 프로세스에 정보를 제공하고 기능의 유용성을 검증하는 데 도움이 됩니다. 의견을 보내는 가장 좋은 방법은 문제를 신고하거나 WebAssembly 커뮤니티 그룹에서 표준화 프로세스에 참여하는 것입니다.