Overdraagbare objecten - Bliksemsnel

Chrome 13 introduceerde het verzenden van ArrayBuffer -bestanden naar/van een webwerker met behulp van een algoritme dat gestructureerd klonen wordt genoemd. Hierdoor kon de postMessage() API berichten accepteren die niet alleen uit tekenreeksen bestonden, maar uit complexe typen zoals File , Blob , ArrayBuffer en JSON-objecten. Gestructureerd klonen wordt ook ondersteund in latere versies van Firefox.

Sneller is beter

Gestructureerd klonen is geweldig, maar het is nog steeds een kopieeroperatie. De overhead van het doorgeven van een ArrayBuffer van 32 MB aan een Worker kan honderden milliseconden bedragen. Nieuwe versies van browsers bevatten een enorme prestatieverbetering voor het doorgeven van berichten, genaamd Transferable Objects .

Bij overdraagbare objecten worden gegevens van de ene context naar de andere overgedragen. Het is zero-copy, wat de prestaties bij het verzenden van gegevens naar een werknemer enorm verbetert. Beschouw het als een pass-by-referentie als je uit de C/C++-wereld komt. In tegenstelling tot pass-by-referentie is de 'versie' uit de aanroepende context echter niet langer beschikbaar zodra deze naar de nieuwe context is overgebracht. Wanneer u bijvoorbeeld een ArrayBuffer van uw hoofdapp naar Worker overzet, wordt de oorspronkelijke ArrayBuffer gewist en niet langer bruikbaar. De inhoud ervan wordt (letterlijk) overgebracht naar de Worker-context.

Om met overdraagbare objecten te spelen, is er een nieuwe versie van postMessage() die overdraagbare objecten ondersteunt:

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

Voor de werksituatie is het eerste argument het ArrayBuffer bericht. Het tweede argument is een lijst met items die moeten worden overgedragen. In dit voorbeeld geeft u de arrayBuffer op in de overdraagbare lijst.

Benchmark-demo

Om de prestatiewinst van overdraagbare bestanden te zien, heb ik een demo samengesteld.

De demo stuurt een ArrayBuffer van 32 MB naar een werker en terug met behulp van postMessage() . Als uw browser geen overdraagbare bestanden ondersteunt, valt het voorbeeld terug op gestructureerd klonen. Gemiddeld vijf keer uitgevoerd in verschillende browsers, dit is wat ik heb:

Vergelijkingstabel voor gestructureerd klonen versus overdraagbare objecten

Op een MacBook Pro/10.6.8/2.53 GHz/Intel Core 2 Duo was FF de snelste met behulp van gestructureerd klonen. Gemiddeld duurde het 302 ms om de ArrayBuffer van 32 MB naar een medewerker te sturen en deze terug te plaatsen in de hoofdthread (RRT - Round Trip Time). Als je dat vergelijkt met overdraagbare bestanden, duurde dezelfde test 6,6 ms. Dat is een enorme prestatieboost!

Met dit soort snelheden kunnen enorme WebGL-texturen/meshes naadloos worden doorgegeven tussen een Worker en de hoofdapp.

Functiedetectie

Het detecteren van functies is hierbij een beetje lastig. Mijn aanbeveling is om een ​​kleine ArrayBuffer naar uw werker te sturen. Als de buffer wordt overgedragen en niet wordt gekopieerd, gaat de .byteLength naar 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.
}

Ondersteuning: momenteel Chrome 17+, Firefox, Opera, Safari en IE10+

Bijgewerkt (13-12-2011): Codefragment om de handtekening webkitPostMessage() weer te geven is verschillend voor venster en werker. Bijgewerkt (03-11-2016): Voorvoegsels van leveranciers verwijderd en codefragmenten bijgewerkt