Obsługa wątków WebAssembly została udostępniona w Chrome 70 w ramach testów pochodzenia.
WebAssembly (Wasm) umożliwia kompilowanie kodu napisanego w C++ i innych językach na potrzeby uruchamiania w internecie. Jedną z bardzo przydatnych funkcji aplikacji natywnych jest możliwość korzystania z wątków – prymitywów do obliczeń równoległych. 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 wersji źródłowej 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 dla WebAssembly. Zachęcamy zainteresowanych deweloperów do korzystania z nich i przesyłania opinii.
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 udostępniają ani skompilowanego kodu, ani obiektów JavaScript, więc nie mogą udostępniać danych zmiennych, takich jak 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. Istnieje wiele bibliotek kodu napisanych w języku C lub C++, które korzystają z pthreads. Można je skompilować do Wasm i uruchamiać w prawdziwym trybie wielowątkowym, co pozwala większej liczbie rdzeni pracować nad tymi samymi danymi jednocześnie.
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_val
i bg_val
. W tym przykładzie jest też funkcja fibonacci()
, która będzie wywoływana 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.
Kompilowanie kodu na potrzeby 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 dla skompilowanego modułu WebAssembly, a argument „-s PTHREAD_POOL_SIZE=2
” informuje kompilator, aby wygenerował pulę 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 jest ich 2). Będą one 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 adres URL about://flags
w przeglądarce, jak pokazano poniżej:
Następnie znajdź eksperymentalne ustawienie wątków WebAssembly, które wygląda tak:
Zmień ustawienie na Włączono, jak pokazano na ilustracji poniżej, a potem uruchom ponownie przeglądarkę.
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ć serwer WWW i wczytać ją z przeglądarki. 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:
Nasz program WebAssembly z wątkami został wykonany. Zachęcamy do wypróbowania własnej aplikacji z nitkami, wykonując czynności opisane powyżej.
Testowanie w warunkach rzeczywistych za pomocą wersji próbnej origin
Testowanie wątków przez włączenie flag eksperymentalnych w przeglądarce jest odpowiednie na potrzeby programowania, 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. Aby to zrobić, musisz uzyskać 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 na potrzeby testowania wersji źródłowej, wypełnij formularz.
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ć to demo.
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.
Chcemy poznać opinie deweloperów, którzy wypróbują tę funkcję, ponieważ pomoże nam to w przeprowadzeniu procesu standaryzacji i sprawdzeniu przydatności tej funkcji. Najlepszym sposobem na przesłanie opinii jest zgłaszanie problemów lub udział w procesie standaryzacji w grupie Community Group WebAssembly.