Kommunikation zwischen Workern

Flash Player 11.4 und höher, Adobe AIR 13.4 und höher für Desktopplattformen

Zwar führen Worker ihren Code in separaten Ausführungsthreads aus, dies wäre aber wenig hilfreich, wenn sie vollständig voneinander isoliert wären. Kommunikation zwischen Workern bedeutet letztendlich das Übergeben von Daten zwischen Workern. Es gibt drei Mechanismen, um Daten von einem Worker zu einem anderen zu bringen.

Bei der Überlegung, welche dieser Techniken zur gemeinsamen Datennutzung für eine bestimmte Datenübergabe die richtige ist, ziehen Sie in Betracht, worin sie sich unterscheiden. Ein Unterschied ist, ob es ein Ereignis gibt, um den Empfänger zu informieren, wenn neue Daten vorliegen, oder ob der empfangende Worker auf Updates überprüfen muss. Ein anderer Unterschied besteht darin, wie die Daten tatsächlich übergeben werden. In einigen Fällen erhält der empfangende Worker eine Kopie der gemeinsam genutzten Daten, was bedeutet, dass mehr Objekte erstellt werden und somit Arbeitsspeicher und CPU stärker beansprucht werden. In anderen Fällen greifen die Worker auf Objekte zu, die auf denselben zugrunde liegenden Systemspeicher verweisen, sodass weniger Objekte erstellt werden und insgesamt weniger Speicher benötigt wird. Diese Unterschiede sind hier herausgestellt:

Kommunikationstechnik

Setzt Ereignis ab, wenn Daten empfangen werden

Nutzt Arbeitsspeicher gemeinsam mit Workern

Von Workern geteilte Eigenschaften

Nein

Nein, Objekte sind Kopien, keine Verweise

MessageChannel

Ja

Nein, Objekte sind Kopien, keine Verweise

Gemeinsam nutzbares ByteArray

Nein

Ja, Speicher wird gemeinsam genutzt

Übergeben von Daten mit einer gemeinsam genutzten Eigenschaft

Die einfachste Möglichkeit, Daten zwischen Workern zu teilen, ist die Verwendung einer gemeinsam genutzten Eigenschaft. Jeder Worker pflegt ein internes Wörterbuch von Werten gemeinsam genutzter Eigenschaften. Diese Eigenschaften werden mit String-Schlüsselnamen gespeichert, um sie zu unterscheiden. Um ein Objekt bei einem Worker als gemeinsam genutzte Eigenschaft zu speichern, rufen Sie die setSharedProperty() -Methode des Worker-Objekts mit zwei Argumenten auf, nämlich dem Schlüsselnamen und dem zu speichernden Wert:

// code running in the parent worker 
bgWorker.setSharedProperty("sharedPropertyName", someObject);

Nachdem die gemeinsam genutzte Eigenschaft eingerichtet wurde, kann der Wert durch einen Aufruf der getSharedProperty() -Methode des Worker-Objekts gelesen werden, wobei der Schlüsselname übergeben wird:

// code running in the background worker 
receivedProperty = Worker.current.getSharedProperty("sharedPropertyName");

Es gibt keine Einschränkungen dafür, welcher Worker den Wert der Eigenschaft liest oder festlegt. Zum Beispiel kann Code in einem Hintergrundworker seine setSharedProperty() -Methode aufrufen, um einen Wert zu speichern. Code, der im übergeordneten Worker ausgeführt wird, kann dann die getSharedProperty() -Eigenschaft verwenden, um die Daten abzurufen.

Der Wert, der an die setSharedProperty() -Methode übergeben wird, kann nahezu jeder Objekttyp sein. Wenn Sie die getSharedProperty() -Methode aufrufen, ist das Objekt, das zurückgegeben wird, eine Kopie des Objekts, das in setSharedProperty() übergeben wurde, und nur in einigen wenigen Sonderfällen ein Verweis auf dasselbe Objekt. Einzelheiten zum Datenaustausch werden unter Gemeinsam genutzte Verweise und kopierte Werte beschrieben.

Der größte Vorteil beim Verwenden einer gemeinsam genutzten Eigenschaft zum Übergeben von Daten zwischen Workern besteht darin, dass diese Methode schon verfügbar ist, bevor der Worker ausgeführt wird. Sie können die setSharedProperty() -Methode eines Hintergrundworkerobjekts aufrufen, um eine gemeinsam genutzte Eigenschaft festzulegen, bevor der Worker ausgeführt wird. Wenn der übergeordnete Worker die start() -Methode des Worker-Objekts aufruft, ruft die Laufzeitumgebung den Hauptklassenkonstruktor des untergeordneten Workers auf. Alle gemeinsam genutzten Eigenschaften, die vor dem Aufruf von start() festgelegt wurden, können vom Code im untergeordneten Worker gelesen werden.

Übergeben von Daten über einen MessageChannel

Ein Nachrichtenkanal ist eine unidirektionale Verbindung zur Datenübergabe zwischen zwei Workern. Das Verwenden eines MessageChannel-Objekts zum Übergeben von Daten zwischen Workern hat einen wichtigen Vorteil. Wenn Sie eine Nachricht (ein Objekt) über einen Nachrichtenkanal senden, setzt das MessageChannel-Objekt ein channelMessage -Ereignis ab. Code im empfangenden Worker kann einen Listener für dieses Ereignis verwenden, um festzustellen, wann Daten verfügbar sind. Auf diese Weise muss der empfangende Worker nicht ständig prüfen, ob Datenaktualisierungen vorliegen.

Ein Nachrichtenkanal ist nur mit zwei Workern verknüpft, einem Sender und einem Empfänger. Um ein MessageChannel-Objekt zu erstellen, rufen Sie die createMessageChannel() -Methode des sendenden Worker-Objekts auf und übergeben den empfangenden Worker als Argument:

// In the sending worker swf 
var sendChannel:MessageChannel; 
sendChannel = Worker.current.createMessageChannel(receivingWorker);

Beide Worker benötigen Zugriff auf das MessageChannel-Objekt. Die einfachste Möglichkeit, dafür zu sorgen, ist die Übergabe des MessageChannel-Objekts mit der setSharedProperty() -Methode:

receivingWorker.setSharedProperty("incomingChannel", sendChannel);

Registrieren Sie im empfangenden Worker einen Listener für das channelMessage -Ereignis des MessageChannel-Objekts. Dieses Ereignis wird abgesetzt, wenn der sendende Worker Daten über den Nachrichtenkanal sendet.

// In the receiving worker swf 
var incomingChannel:MessageChannel; 
incomingChannel = Worker.current.getSharedProperty("incomingChannel"); 
incomingChannel.addEventListener(Event.CHANNEL_MESSAGE, handleIncomingMessage);

Zum eigentlichen Senden der Daten rufen Sie im sendenden Worker die send() -Methode des MessageChannel-Objekts auf:

// In the sending worker swf 
sendChannel.send("This is a message");

Im empfangenden Worker ruft das MessageChannel-Objekt die channelMessage -Ereignisprozedur auf. Der empfangende Worker kann die Daten dann abrufen, indem er die receive() -Methode des MessageChannel-Objekts aufruft.

private function handleIncomingMessage(event:Event):void 
{ 
    var message:String = incomingChannel.receive() as String; 
}

Das von der receive()-Methode zurückgegebene Objekt weist denselben Datentyp auf wie das Objekt, das an die send() -Methode übergeben wurde. Das empfangene Objekt ist eine Kopie des Objekts, das vom Sender übergeben wurde und kein Verweis auf das Objekt im sendenden Worker. Eine Ausnahme sind lediglich einige wenige Datentypen, die unter Gemeinsam genutzte Verweise und kopierte Werte beschrieben werden.

Teilen von Daten mit einem gemeinsam nutzbaren ByteArray

Wenn ein Objekt zwischen zwei Workern übergeben wird, erhält der empfangende Worker ein neues Objekt, das eine Kopie des Originalobjekts ist. Die beiden Objekte werden an unterschiedlichen Orten im Systemspeicher gespeichert. Jede Kopie des empfangenen Objekts erhöht demzufolge die Gesamtspeichernutzung durch die Laufzeitumgebung. Außerdem betreffen Änderungen, die Sie in einem Worker an einem Objekt vornehmen, die Kopie dieses Objekts im anderen Worker nicht. Ausführlichere Informationen dazu, wie Daten kopiert werden, finden Sie unter Gemeinsam genutzte Verweise und kopierte Werte .

Standardmäßig verwendet ein ByteArray-Objekt dasselbe verhalten. Wenn Sie eine ByteArray-Instanz an die setSharedProperty() -Methode eines Worker-Objekts oder an die send() -Methode eines MessageChannel-Objekts übergeben, erstellt die Laufzeitumgebung ein neues ByteArray im Arbeitsspeicher des Computers. Der empfangende Worker erhält eine ByteArray-Instanz, die ein Verweis auf dieses neue ByteArray ist. Sie können dieses Verhalten eines ByteArray-Objekts ändern, indem Sie seine shareable -Eigenschaft auf true einstellen.

Wenn ein gemeinsam nutzbares ByteArray-Objekt von einem Worker zum anderen übergeben wird, ist die ByteArray-Instanz im empfangenden Worker ein Verweis auf denselben zugrunde liegenden Systemspeicher, der von der ByteArray-Instanz im sendenden Worker verwendet wird. Wenn Code in einem Worker den Inhalt des Bytearrays ändert, sind diese Änderungen sofort in anderen Workern verfügbar, die Zugriff auf dieses gemeinsam genutzte Bytearray haben.

Da Worker ihren Code gleichzeitig ausführen, ist es möglich, dass zwei Worker zur selben Zeit versuchen, auf dieselben Bytes in einem Bytearray zuzugreifen. Dies kann zu Datenverlust oder Beschädigungen führen. Es gibt verschiedene APIs, mit denen Sie den Zugriff auf gemeinsam genutzte Ressourcen verwalten und derartige Probleme vermeiden können.

Die ByteArray-Klasse enthält Methoden, mit denen Sie den Inhalt des Bytearrays in einem einzigen Vorgang validieren und ändern können:

Zusätzlich enthält das flash.concurrent-Paket Klassen, die die Zugriffssteuerung beim Arbeiten mit gemeinsam genutzten Ressourcen ermöglichen:

Gemeinsam genutzte Verweise und kopierte Werte

Wenn Sie Worker.setSharedProperty() oder MessageChannel.send() aufrufen, wird das Objekt, das an den empfangenden Worker übergeben wird, im Normalfall übergeben, indem es im AMF-Format serialisiert wird. Dies hat einige Konsequenzen:

  • Das Objekt, das im empfangenden Worker erstellt wird, wenn die getSharedProperty() -Methode aufgerufen wird, wird aus den AMF-Bytes deserialisiert. Es handelt sich um eine Kopie des Originalobjekts, nicht um einen Verweis auf das Objekt. Änderungen, die in einem der beiden Worker am Objekt vorgenommen werden, erfolgen nicht in der Kopie im jeweils anderen Worker.

  • Objekte, die nicht in das AMF-Format serialisiert werden können, wie zum Beispiel Anzeigeobjekte, können nicht mit den Methoden Worker.setSharedProperty() oder MessageChannel.send() an einen Worker übergeben werden.

  • Damit eine benutzerdefinierte Klasse korrekt deserialisiert werden kann, muss die Klassendefinition mit der flash.net.registerClassAlias() -Funktion oder unter Verwendung von [RemoteClass] -Metadaten registriert werden. Es muss derselbe Alias für die Klassenversionen beider Worker verwendet werden.

Es gibt fünf Sonderfälle von Objekten, die tatsächlich gemeinsam genutzt und nicht zwischen Workern kopiert werden:

  • Worker-Objekte

  • MessageChannel-Objekte

  • gemeinsam nutzbares Bytearray (ein ByteArray-Objekt, dessen shareable -Eigenschaft den Wert true hat)

  • Mutex-Objekte

  • Condition-Objekte

Wenn Sie eine Instanz eines dieser Objekte mit der Worker.setSharedProperty() -Methode oder der MessageChannel.send() -Methode übergeben, hat jeder Worker einen Verweis auf dasselbe zugrunde liegende Objekt. Änderungen, die in einem Worker an einer Instanz vorgenommen werden, sind sofort auch in den anderen Workern verfügbar. Wenn Sie dieselbe Instanz eines dieser Objekte mehrmals an einen Worker übergeben, erstellt die Laufzeitumgebung keine neue Kopie des Objekts im empfangenden Worker. Stattdessen wird derselbe Verweis wiederverwendet.

Weitere Techniken der gemeinsamen Datennutzung

Neben den workerspezifischen Mechanismen für die Datenübergabe können Worker Daten auch mit allen vorhanden APIs austauschen, die die gemeinsame Datennutzung zwischen zwei SWF-Dateien unterstützen, zum Beispiel:

  • lokale gemeinsame Objekte

  • Daten in eine Datei in einem Worker schreiben und aus der Datei in einem anderen Worker lesen

  • Daten in eine SQLite-Datenbank schreiben und Daten daraus lesen

Wenn Sie eine Ressource mit mehreren Workern gemeinsam nutzen, müssen Sie im Allgemeinen vermeiden, dass mehrere Worker zur selben Zeit auf die Ressource zugreifen. Es kann zum Beispiel zu Datenverlusten oder -beschädigungen kommen, wenn mehrere Worker gleichzeitig auf eine Datei im lokalen Dateisystem zugreifen. Dies wird auch nicht von allen Betriebssystemen unterstützt.

Zur Vermeidung von Problemen mit gleichzeitigem (parallelem) Zugriff verwenden Sie die Mutex- und die Condition-Klasse im flash.concurrent-Paket, um den Zugriff auf gemeinsam genutzte Ressourcen zu steuern.

Anders als andere Mechanismen für die gemeinsame Datennutzung ist die SQLite-Datenbank für den gleichzeitigen (parallelen) Zugriff ausgelegt und verfügt über eigene integrierte Transaktionsunterstützung. Mehrere Worker können auf eine SQLite-Datenbank zugreifen, ohne die Beschädigung der Daten zu riskieren. Da die Worker unterschiedliche SQLConnection-Instanzen verwenden, greift jeder Worker in einer separaten Transaktion auf die Datenbank zu. Die Integrität der Daten wird durch die gleichzeitig stattfindenden Datenbearbeitungsoperationen nicht beeinträchtigt.

Siehe auch

Arbeiten mit lokalen SQL-Datenbanken in AIR

flash.concurrent-Paket