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 testów pochodzenia.

Alex Danilo

WebAssembly (Wasm) umożliwia kompilację kodu napisanego w języku C++ i innych językach do uruchamiania w internecie. Jedną z bardzo przydatnych funkcji aplikacji natywnych jest możliwość używania wątków – czyli elementu podstawowego do równoległego przetwarzania danych. Większość programistów C i C++ zna interfejs pthreads, który jest standaryzowanym interfejsem API do zarządzania wątkami w aplikacji.

Grupa Wspólnoty WebAssembly pracowała nad wprowadzeniem wątków do sieci, aby umożliwić tworzenie prawdziwych aplikacji wielowątkowych. W ramach tych działań V8 wprowadziło niezbędne wsparcie dla wątków w silniku WebAssembly, dostępne w ramach Origin Trial. Testy pochodzenia umożliwiają deweloperom eksperymentowanie z nowymi funkcjami internetowymi, zanim zostaną one w pełni ustandaryzowane. Dzięki temu możemy zbierać opinie od odważnych deweloperów, które są kluczowe dla weryfikacji i ulepszania nowych funkcji.

Wersja Chrome 70 obsługuje wątki w WebAssembly. Zachęcamy więc zainteresowanych deweloperów, by zaczęli korzystać z nich i przesyłali nam opinie.

Wątki? A co z pracownikami?

Przeglądarki obsługują równoległość za pomocą Web Workers od 2012 roku w Chrome 4. Zwykle używa się też terminów takich jak „w głównym wątku” itp. Jednak Web Workers nie udostępniają sobie danych zmiennych, a zamiast tego komunikują się za pomocą przekazywania wiadomości. W rzeczywistości Chrome przydziela nowy silnik V8 do każdego z nich (nazywanych izolatorami). Izolacje nie współdzielą ani skompilowanego kodu, ani obiektów JavaScript, więc nie mogą udostępniać zmiennych danych, np. pthreads.

Z drugiej strony wątki WebAssembly to wątki, które mogą współdzielić pamięć Wasm. Podstawowe przechowywanie współdzielonej pamięci jest realizowane za pomocą SharedArrayBuffer, czyli prymitywu JavaScriptu, który umożliwia współdzielenie zawartości pojedynczego ArrayBuffer jednocześnie między instancjami roboczymi. Każdy wątek WebAssembly działa w ramach Web Workera, ale współdzielona pamięć Wasm pozwala mu działać podobnie jak na platformach natywnych. Oznacza to, że aplikacje korzystające z wątków Wasm są odpowiedzialne za zarządzanie dostępem do współdzielonej pamięci tak jak w każdej tradycyjnej aplikacji wielowątkowej. Jest wiele istniejących bibliotek kodu napisanych w języku C lub C++, które korzystają z tagów pthreads. Można je skompilować do Wasm i uruchomić w trybie prawdziwych wątków, co pozwoli 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 zaczyna się od funkcji main(), która deklaruje 2 zmiennych fg_valbg_val. Istnieje też funkcja fibonacci(), która w tym przykładzie zostanie wywołana przez oba wątki. Funkcja main() tworzy wątek w tle za pomocą funkcji pthread_create(), której zadaniem jest obliczenie wartości ciągu liczb Fibonacciego odpowiadającej wartości zmiennej bg_val. Funkcja main() działająca w wątku w tle oblicza ją dla zmiennej fg_val. Po zakończeniu działania wątku w tle wyniki są drukowane.

Kompilacja dla obsługi wątków

Najpierw musisz mieć zainstalowany pakiet emscripten SDK, najlepiej w wersji 1.38.11 lub nowszej. Aby skompilować przykładowy kod z włączonymi wątkami do uruchomienia w przeglądarce, musimy przekazać kilka dodatkowych flag kompilatorowi emscripten emcc. Nasz wiersz polecenia 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 2 wątków.

Gdy program zostanie uruchomiony, wczyta on moduł WebAssembly, utworzy Web Workera dla każdego wątku w pulach wątków i udostępni moduł wszystkim workerom (w tym przypadku są to 2 workery), które będą używane za każdym razem, gdy zostanie wywołana funkcja pthread_create(). Każdy worker instancjuje moduł Wasm z tą samą pamięcią, co umożliwia im współpracę. Najnowsze zmiany w V8 w wersji 7.0 udostępniają skompilowany kod natywny modułów Wasm, które są przekazywane między wątkami, co pozwala skalować nawet bardzo duże aplikacje do wielu wątków. Pamiętaj, że rozmiar puli wątków powinien być równy maksymalnej liczbie wątków potrzebnych aplikacji, ponieważ w przeciwnym razie utworzenie wątku może się nie udać. Jeśli jednak rozmiar puli wątków jest zbyt duży, będziesz tworzyć niepotrzebnych pracowników sieciowych, którzy będą zajmować pamięć, nie wykonując przy tym żadnych działań.

Jak wypróbować

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

Strona flag w Chrome

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

Ustawienie wątków WebAssembly

Zmień ustawienie na Włączono, jak pokazano na ilustracji poniżej, a potem uruchom ponownie przeglądarkę.

Włączone ustawienie wątków WebAssembly

Po ponownym uruchomieniu przeglądarki możemy spróbować załadować wątkowy moduł WebAssembly za pomocą minimalnej strony HTML zawierającej tylko te treści:

<!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 DevTools spowoduje wyświetlenie danych wyjściowych z uruchomienia. W konsoli powinno pojawić się coś podobnego do obrazu danych wyjściowych poniżej:

Dane wyjściowe konsoli z programu fibonacci

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

Testowanie w terenie z pierwotnym systemem próbnym

Testowanie wątków przez włączenie flag eksperymentalnych w przeglądarce jest odpowiednie do celów programistycznych, ale jeśli chcesz przetestować aplikację w praktyce, możesz to zrobić za pomocą testu pochodzenia.

Testy Origin umożliwiają wypróbowanie eksperymentalnych funkcji przez użytkowników. Wystarczy, że uzyskasz token testowy powiązany z Twoją domeną. Następnie możesz wdrożyć aplikację i oczekiwać, że będzie działać w przeglądarce, która obsługuje testowaną funkcję (w tym przypadku od wersji Chrome 70). Aby uzyskać własny token do uruchomienia wersji próbnej origin, użyj tego formularza.

Opublikowaliśmy nasze proste przykłady za pomocą tokena próbnego pochodzenia, aby można było je wypróbować bez konieczności tworzenia czegokolwiek.

Jeśli chcesz zobaczyć, co 4 wątki działające równolegle mogą zrobić z grafiką ASCII, musisz też obejrzeć ten pokaz demonstracyjny.

Prześlij nam opinię

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

Czekamy na opinie deweloperów, którzy testują tę funkcję, ponieważ pomogą nam to w procesie standaryzacji i weryfikowaniu jej przydatności. Najlepszym sposobem na przesłanie opinii jest zgłaszanie problemów lub udział w procesie standaryzacji w grupie Community Group WebAssembly.