Übertragbare Objekte – blitzschnell

In Chrome 13 wurde ein Algorithmus namens strukturiertes Klonen entwickelt, mit dem ArrayBuffers an einen oder von einem Web Worker gesendet werden können. Dadurch konnte die postMessage() API Nachrichten akzeptieren, die nicht nur Strings, sondern komplexe Typen wie File, Blob, ArrayBuffer und JSON-Objekte waren. Strukturiertes Klonen wird auch in späteren Versionen von Firefox unterstützt.

Schneller ist besser

Strukturiertes Klonen ist großartig, aber es ist noch ein Kopiervorgang. Der Aufwand für die Übergabe von 32 MB ArrayBuffer an einen Worker kann Hunderte von Millisekunden betragen. Neue Browserversionen enthalten eine erhebliche Leistungsverbesserung für die Nachrichtenweitergabe, die als übertragbare Objekte bezeichnet wird.

Bei übertragbaren Objekten werden Daten von einem Kontext in einen anderen übertragen. Dabei handelt es sich um Zero-Copy-Verfahren, was die Leistung beim Senden von Daten an einen Worker erheblich verbessert. Betrachten Sie es als Referenz, wenn Sie aus der C/C++-Welt kommen. Im Gegensatz zur Pass-by-Referenz ist die „Version“ aus dem aufrufenden Kontext jedoch nicht mehr verfügbar, nachdem sie in den neuen Kontext übertragen wurde. Wenn beispielsweise ein ArrayBuffer von Ihrer Haupt-App zu Worker übertragen wird, wird die ursprüngliche ArrayBuffer gelöscht und kann nicht mehr verwendet werden. Sein Inhalt wird (im wahrsten Sinne des Wortes leise) an den Worker-Kontext übertragen.

Es gibt eine neue Version von postMessage(), die übertragbare Objekte unterstützt:

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

Im Worker-Fall ist das erste Argument die Nachricht ArrayBuffer. Das zweite Argument ist eine Liste von Elementen, die übertragen werden sollen. In diesem Beispiel geben Sie arrayBuffer in der Liste der übertragbaren Daten an.

Benchmark-Demo

Ich habe eine Demo erstellt, um die Leistungssteigerungen bei übertragbaren Inhalten zu sehen.

In der Demo werden 32 MB ArrayBuffer an einen Worker und zurück über postMessage() gesendet. Wenn dein Browser keine übertragbaren Inhalte unterstützt, wird im Beispiel das strukturierte Klonen verwendet. Durchschnittlich 5 wird in verschiedenen Browsern ausgeführt. Folgendes habe ich gefunden:

Vergleichsdiagramm: Klonen strukturierter und übertragbarer Objekte

Auf einem MacBook Pro/10.6.8/2, 53 GHz/Intel Core 2 Duo war FF mit strukturiertem Klonen am schnellsten. Im Durchschnitt hat es 302 ms gedauert, die 32 MB ArrayBuffer an einen Worker zu senden und sie zurück an den Hauptthread (RRT – Round Trip Time) zu senden. Im Vergleich dazu dauerte derselbe Test 6, 6 ms. Das ist ein enormer Leistungsschub!

Dank dieser Geschwindigkeiten können große WebGL-Texturen/-Maschen nahtlos zwischen einem Worker und einer Haupt-App übertragen werden.

Funktionserkennung

Dabei ist die Funktionserkennung etwas kompliziert. Ich empfehle Ihnen, eine kleine ArrayBuffer an Ihren Worker zu senden. Wenn der Zwischenspeicher übertragen und nicht kopiert wird, wird .byteLength auf 0 gesetzt:

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

Support: Derzeit Chrome 17 oder höher, Firefox, Opera, Safari und Internet Explorer 10 oder höher

Aktualisiert (13.12.2011): Das Code-Snippet zum Anzeigen der webkitPostMessage()-Signatur unterscheidet sich für Fenster und Worker. Aktualisiert (03.11.2016): Anbieterpräfixe und aktualisierte Code-Snippets wurden entfernt.