Wątki WebAssembly gotowe do wypróbowania w Chrome 70

Obsługa wątków WebAssembly została udostępniona w Chrome 70 w ramach wersji próbnej origin.

Alex Danilo

WebAssembly (Wasm) umożliwia kompilację kodu napisanego w C++ i innych językach do uruchamiania w internecie. Jedną z przydatnych funkcji aplikacji natywnych jest możliwość korzystania z wątków – elementów podstawowych do obliczeń równoległych. Większość programistów C i C++ zna już pthreads, ustandaryzowany interfejs API do zarządzania wątkami w aplikacji.

Grupa społeczności WebAssembly pracuje nad przeniesieniem wątków do internetu, aby umożliwić działanie prawdziwych aplikacji wielowątkowych. W ramach tych działań wdrożyliśmy niezbędną obsługę wątków w silniku WebAssembly, która jest dostępna w wersji próbnej origin. Wersje próbne origin pozwalają deweloperom testować nowe funkcje internetowe, zanim staną się one w pełni ujednolicone. Dzięki temu możemy gromadzić rzeczywiste opinie od nieustraszonych programistów, co ma kluczowe znaczenie przy sprawdzaniu i ulepszaniu nowych funkcji.

Wersja Chrome 70 obsługuje wątki dla WebAssembly, dlatego zachęcamy zainteresowanych deweloperów do korzystania z nich i przekazywania nam opinii.

Wątki? A co z pracownikami?

Przeglądarki od 2012 r. w Chrome 4 obsługują równoległość za pomocą Web Workers. To normalne, że słyszenie haseł takich jak „w wątku głównym” itp. nie są jednak udostępniane między nimi, a komunikacja polega na przekazywaniu wiadomości. Chrome przydziela do każdego z nich nowy silnik V8 (nazywany izolacją). Izolacje nie współdzielą skompilowanego kodu ani obiektów JavaScript, więc nie mogą udostępniać zmiennych danych, takich jak pthreads.

Wątki WebAssembly to natomiast wątki, które mogą korzystać z tej samej pamięci Wasm. Podstawowe przechowywanie pamięci współdzielonej jest realizowane za pomocą obiektu SharedArrayBuffer, czyli podstawowego JavaScriptu, który umożliwia udostępnianie zawartości pojedynczego bufora ArrayBuffer równolegle między instancjami roboczymi. Każdy wątek WebAssembly jest uruchamiany w instancji Web Worker, ale współdzielona pamięć Wasm umożliwia pracę podobnie jak na platformach natywnych. Oznacza to, że aplikacje używające wątków Wasm odpowiadają za zarządzanie dostępem do pamięci współdzielonej, tak jak w przypadku każdej tradycyjnej aplikacji z wątkami. Istnieje wiele istniejących bibliotek kodu napisanych w językach C lub C++, które korzystają z metody pthreads. Można je skompilować do Wasm i uruchomić w trybie z wątkami prawdziwymi, co pozwala większej liczbie rdzeni jednocześnie pracować na tych samych danych.

Prosty przykład

Oto przykład prostego programu „C”, który używa wątków.

#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;
}

Kod ten zaczyna się od funkcji main(), która deklaruje 2 zmienne fg_val i bg_val. Istnieje też funkcja o nazwie fibonacci(), która zostanie wywołana przez oba wątki w tym przykładzie. Funkcja main() tworzy wątek w tle za pomocą funkcji pthread_create(), której zadanie polega na obliczaniu ciągu liczby fibonacci odpowiadającej wartości zmiennej bg_val. Tymczasem funkcja main() działająca w wątku na pierwszym planie oblicza ją dla zmiennej fg_val. Po zakończeniu działania wątku w tle wyniki zostaną wydrukowane.

Kompilacja pod kątem obsługi wątków

Najpierw musisz zainstalować emscripten SDK, najlepiej w wersji 1.38.11 lub nowszej. Aby utworzyć przykładowy kod z włączoną obsługą wątków w przeglądarce, musimy przekazać kilka dodatkowych flag do kompilatora emscripten emcc. Wiersz poleceń wygląda tak:

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

Argument wiersza poleceń „-s USE_PTHREADS=1” włącza obsługę wątków w skompilowanym module WebAssembly, a argument „-s PTHREAD_POOL_SIZE=2” nakazuje kompilatorowi wygenerowanie puli dwóch (2) wątków.

Po uruchomieniu programu wczyta on moduł WebAssembly, utworzy instancje robocze dla każdego wątku w puli wątków, udostępnisz go każdej instancji roboczej (w tym przypadku będzie to 2 – będą one używane przy każdym wywołaniu narzędzia pthread_create()). Każda instancja robocza tworzy instancję modułu Wasm z tą samą pamięcią, co umożliwia współpracę. Najnowsze zmiany w wersji 7.0 w V8 korzystają ze skompilowanego kodu natywnego modułów Wasm przekazywanych między instancjami roboczymi, dzięki czemu można skalować nawet bardzo duże aplikacje do wielu instancji roboczych. Pamiętaj, że rozmiar puli wątków powinien być równy maksymalnej liczbie wątków, których potrzebuje Twoja aplikacja. W przeciwnym razie utworzenie wątków może się nie udać. Jednocześnie, jeśli rozmiar puli wątków jest za duży, utworzysz niepotrzebne zasoby robocze, które będą zajmować się tylko pamięcią.

Jak to wypróbować

Najszybszym sposobem przetestowania modułu WebAssembly jest włączenie eksperymentalnej obsługi wątków WebAssembly w Chrome 70 i nowszych wersjach. Otwórz w przeglądarce adres URL about://flags, tak jak poniżej:

Strona flag Chrome

Następnie znajdź eksperymentalne ustawienie wątków WebAssembly, które będzie wyglądać tak:

Ustawienie wątków WebAssembly

Zmień ustawienie na Włączone, jak pokazano poniżej, a następnie ponownie uruchom przeglądarkę.

Ustawienie wątków WebAssembly włączone

Po ponownym uruchomieniu przeglądarki możemy spróbować wczytać z wątkami moduł WebAssembly z minimalną stroną HTML zawierającą tylko tę treść:

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

Aby wypróbować tę stronę, musisz uruchomić jakiś serwer WWW i wczytać go w przeglądarce. Spowoduje to załadowanie i uruchomienie modułu WebAssembly. Otwarcie Narzędzi deweloperskich pokazuje dane wyjściowe z biegu. W konsoli powinien być widoczny podobny do tego obraz wyjściowy:

Dane wyjściowe konsoli z programu Fibonacci

Nasz program WebAssembly z wątkami został wykonany. Zachęcamy do wypróbowania własnej aplikacji w wątkach, wykonując czynności opisane powyżej.

Testowanie w terenie za pomocą wersji próbnej Origin

Testowanie wątków przez włączenie flag eksperymentalnych w przeglądarce to dobre rozwiązanie do celów programistycznych, ale jeśli chcesz przetestować swoją aplikację, możesz to zrobić, korzystając z tzw. testu origin.

Testowanie origin pozwala wypróbować funkcje eksperymentalne użytkownikom przez uzyskanie tokena testowego powiązanego z Twoją domeną. Następnie możesz wdrożyć aplikację i oczekiwać, że będzie działać w przeglądarce obsługującej testowaną funkcję (w tym przypadku od Chrome 70). Aby uzyskać własny token do uruchomienia wersji próbnej origin, użyj tego formularza.

Powyższy prosty przykład umieściliśmy przy użyciu tokena testowania origin, dzięki czemu możesz przetestować to samodzielnie bez konieczności tworzenia niczego.

Jeśli chcesz sprawdzić, co 4 wątki uruchomione równolegle mogą zrobić w przypadku grafiki ASCII, obejrzyj też tę prezentację.

Podziel się opinią

Wątki WebAssembly to nowy, bardzo przydatny element podstawowy do przenoszenia aplikacji do internetu. Teraz w środowisku WebAssembly można uruchamiać aplikacje i biblioteki w językach C oraz C++, które wymagają obsługi pthreads.

Potrzebujemy opinii deweloperów, którzy testują tę funkcję, ponieważ pomogą one w informowaniu o procesie standaryzacji i sprawdzeniu jej przydatności. Najlepszym sposobem na przesłanie opinii jest zgłoszenie problemów lub zaangażowanie się w proces standaryzacji w grupie społeczności WebAssembly.