Obiekty, które można przenieść – błyskawiczna

W Chrome 13 wprowadzono wysyłanie żądań ArrayBuffer do i z instancji roboczej Web Worker za pomocą algorytmu o nazwie klonowanie ustrukturyzowane. Dzięki temu interfejs API postMessage() akceptował wiadomości, które nie były tylko ciągami tekstowymi, ale typy złożone, takie jak File, Blob, ArrayBuffer i obiekty JSON. Klonowanie uporządkowane jest też obsługiwane w nowszych wersjach Firefoksa.

Szybciej znaczy lepiej

Klonowanie uporządkowane to świetna sprawa, ale nadal jest to operacja kopiowania. Narzut danych ArrayBuffer o rozmiarze 32 MB do instancji roboczej może wynosić setki milisekund. Nowe wersje przeglądarek zapewniają znaczący wzrost wydajności przekazywania wiadomości, zwany obiektami z możliwością przenoszenia.

W przypadku obiektów przenoszonych dane są przenoszone z jednego kontekstu do drugiego. To zero-kopia, która znacznie poprawia wydajność wysyłania danych do instancji roboczej. Jeśli pochodzisz ze świata C/C++, możesz myśleć o tym jako o przekazywanym w ten sposób pliku referencyjnym. Jednak w przeciwieństwie do przekazywania dalej, „wersja” z kontekstu wywołania nie jest już dostępna po przeniesieniu do nowego kontekstu. Na przykład podczas przenoszenia elementu ArrayBuffer z aplikacji głównej do instancji roboczej pierwotny plik ArrayBuffer zostaje wyczyszczony i nie można go już używać. Jego zawartość jest przenoszona (dosłownie) do kontekstu instancji roboczej.

Jeśli chcesz grać z materiałami przenoszonymi, jest dostępna nowa wersja postMessage(), która obsługuje te obiekty:

worker.postMessage(arrayBuffer, [transferableList]);
window.postMessage(arrayBuffer, targetOrigin, [transferableList]);

W przypadku instancji roboczych pierwszy argument to komunikat ArrayBuffer. Drugi argument to lista elementów do przesłania. W tym przykładzie podasz arrayBuffer na liście możliwych do przeniesienia.

Demonstracja

Przygotowałem prezentację, aby sprawdzić wzrost wydajności urządzeń przenoszonych.

Wersja demonstracyjna wysyła ArrayBuffer o wielkości 32 MB do instancji roboczej i z powrotem za pomocą postMessage(). Jeśli Twoja przeglądarka nie obsługuje elementów z możliwością przeniesienia, w przykładzie pojawia się ustrukturyzowane klonowanie. Średnio 5 działań w różnych przeglądarkach wygląda tak:

Wykres porównawczy z klonowaniem uporządkowanych danych i obiektami z możliwością przeniesienia

Na komputerach MacBook Pro/10.6.8/2, 53 GHz/Intel Core 2 Duo najszybszym sposobem na wykorzystanie klonowania strukturalnego było FF. Wysłanie pliku ArrayBuffer o wielkości 32 MB do pracownika i opublikowanie go w wątku głównym trwało średnio 302 ms (RRT – czas w obie strony). Dla porównania z tymi z możliwością przeniesienia ten sam test trwał 6, 6 ms. To wielki wzrost wydajności!

Przy takich prędkościach ogromne tekstury i siatki WebGL mogą być płynnie przekazywane między platformą roboczą a aplikacją główną.

Wykrywanie funkcji

W tym przypadku wykrywanie funkcji jest nieco skomplikowane. Zalecamy wysłanie do pracownika niewielkiego dodatku ArrayBuffer. Jeśli bufor został przeniesiony, a nie skopiowany, jego .byteLength otrzyma wartość 0:

var ab = new ArrayBuffer(1);
worker.postMessage(ab, [ab]);
if (ab.byteLength) {
    alert('Transferables are not supported in your browser!');
} else {
    // Transferables are supported.
}

Obsługa: Chrome 17 i nowsze wersje, Firefox, Opera, Safari oraz IE10 i nowsze

Aktualizacja (13.12.2011): fragment kodu pokazujący podpis webkitPostMessage() jest inny w przypadku okna i instancji roboczej. Aktualizacja (03.11.2016): usunęliśmy prefiksy dostawców i zaktualizowane fragmenty kodu