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

WebAssembly 스레드 지원은 오리진 트라이얼의 일환으로 Chrome 70에서 제공됩니다.

Alex Danilo

WebAssembly (Wasm)를 사용하면 C++ 및 기타 언어로 작성된 코드를 컴파일하여 웹에서 실행할 수 있습니다. 네이티브 애플리케이션의 매우 유용한 기능 중 하나는 병렬 계산의 기본 요소인 스레드를 사용하는 것입니다. 대부분의 C 및 C++ 개발자는 애플리케이션의 스레드 관리를 위한 표준화된 API인 pthreads에 익숙할 것입니다.

WebAssembly 커뮤니티 그룹은 실제 멀티스레드 애플리케이션을 지원하기 위해 웹에 스레드를 가져오기 위해 노력하고 있습니다. 이러한 노력의 일환으로 V8은 오리진 트라이얼을 통해 제공되는 WebAssembly 엔진의 스레드에 필요한 지원을 구현했습니다. 오리진 트라이얼을 통해 개발자는 새로운 웹 기능을 완전히 표준화하기 전에 실험해 볼 수 있습니다. 이를 통해 용감한 개발자로부터 실제적인 의견을 수집할 수 있으며, 이는 새로운 기능을 검증하고 개선하는 데 중요합니다.

Chrome 70 버전은 WebAssembly용 스레드를 지원하므로 관심 있는 개발자는 스레드를 사용해 보고 의견을 보내 주시기 바랍니다.

대화목록, 작업자의 경우는 어떨까요?

2012년부터 Chrome 4에서 브라우저는 웹 작업자를 통한 동시 로드를 지원했습니다. 실제로 '기본 스레드에서'와 같은 용어는 일반적으로 듣게 됩니다. 하지만 웹 작업자는 변경 가능한 데이터를 공유하지 않고 통신에 메시지 전달을 사용합니다. 실제로 Chrome은 각각에 새로운 V8 엔진 (격리라고 함)을 할당합니다. 격리된 코드는 컴파일된 코드나 JavaScript 객체를 공유하지 않으므로 pthread와 같은 변경 가능한 데이터를 공유할 수 없습니다.

반면 WebAssembly 스레드는 동일한 Wasm 메모리를 공유할 수 있는 스레드입니다. 공유 메모리의 기본 저장소는 단일 ArrayBuffer의 콘텐츠를 작업자 간에 동시에 공유할 수 있게 해주는 자바스크립트 프리미티브인 SharedArrayBuffer로 실행됩니다. 각 WebAssembly 스레드는 Web Worker에서 실행되지만 공유된 Wasm 메모리를 통해 네이티브 플랫폼에서 하는 것처럼 작동할 수 있습니다. 즉, Wasm 스레드를 사용하는 애플리케이션은 기존 스레드 애플리케이션에서처럼 공유 메모리에 관한 액세스를 관리합니다. pthreads를 사용하는 C 또는 C++로 작성된 많은 기존 코드 라이브러리가 있으며, 이러한 코드 라이브러리는 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;
}

이 코드는 2개의 변수 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 이상)에서 작동할 것으로 예상할 수 있습니다. 자체 토큰을 받아 오리진 트라이얼을 실행하려면 여기에서 신청 양식을 사용하세요.

위의 간단한 예는 오리진 트라이얼 토큰을 사용하여 호스팅했으므로 아무것도 빌드하지 않고도 직접 사용해 볼 수 있습니다.

ASCII 아트에 대해 병렬로 실행되는 4개의 스레드가 무엇을 할 수 있는지 확인하려면 이 데모를 살펴봐야 합니다.

의견 보내기

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

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