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:
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
|
|
|