Communicatie tussen workers

Flash Player 11.4 of hoger, Adobe AIR 13.4 of hoger voor desktopplatforms

Alhoewel workers hun code uitvoeren in afzonderlijke uitvoeringsthreads, zou het weinig voordeel opleveren als dit volledig geïsoleerd gebeurt. Communicatie tussen workers betekent dan ook dat gegevens tussen de workers wordt doorgegeven. Er zijn drie werkwijzen om de gegevens van één worker door te geven aan andere workers.

Als u beslist welke van deze technieken voor gegevensdeling geschikt is voor een specifieke gegevensdoorgiftebehoefte, houdt u rekening met de twee belangrijkste verschillen in deze technieken. Eén verschil is of er al dan niet een gebeurtenis is om de ontvanger te melden dat er nieuwe gegevens beschikbaar zijn en of de ontvangende worker al dan niet controleren op updates. Een ander verschil tussen deze technieken voor gegevensdeling heeft betrekking op de manier waarop de gegevens worden doorgegeven. In sommige gevallen is de ontvangende worker een kopie van de gedeelde gegevens, wat betekent dat er meer objecten worden gemaakt die gebruikmaken van het geheugen en CPU-cycli. In andere gevallen krijgen workers toegang tot objecten die verwijzen naar hetzelfde onderliggende systeemgeheugen, wat betekent dat er minder objecten worden gemaakt en er dus minder geheugen wordt gebruikt. De verschillen worden hier opgesomd:

Communicatietechniek

Verstuurt gebeurtenis bij ontvangst van gegevens

Deelt geheugen tussen workers

Gedeelde eigenschappen tussen workers

Nee

Nee, objecten zijn kopieën, geen verwijzingen

MessageChannel

Ja

Nee, objecten zijn kopieën, geen verwijzingen

Deelbare ByteArray

Nee

Ja, geheugen wordt gedeeld

Gegevens doorgeven met een gedeelde eigenschap

De eenvoudigste manier om gegevens tussen workers te delen is via een gedeelde eigenschap. Elke worker beheert een intern woordenboek met gedeelde eigenschapswaarden. De eigenschappen zijn opgeslagen met sleutelnamen in tekenreeksindeling om ze te onderscheiden van andere eigenschappen. Als u een object in een worker wilt opslaan als gedeelde eigenschap, moet u de methode setSharedProperty() van het Worker-object aanroepen met behulp van twee argumenten, de sleutelnaam en de waarde die moet worden opgeslagen:

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

Wanneer de gedeelde eigenschap is ingesteld, kan de waarde worden gelezen door de methode getSharedProperty() van het Worker-object aan te roepen en de sleutelnaam door te geven:

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

Het maakt niet uit welke worker de eigenschapswaarde instelt of leest. Zo kan code in een worker op de achtergrond bijvoorbeeld zijn eigen methode setSharedProperty() aanroepen om een waarde op te slaan. Vervolgens kan de code die wordt uitgevoerd in de bovenliggende worker, de methode getSharedProperty() aanroepen om de gegevens te ontvangen.

Praktisch elk type object kan als waarde worden doorgegeven aan de methode setSharedProperty() . Wanneer u de methode getSharedProperty() aanroept, bestaat het geretourneerde object uit een kopie van het object dat wordt doorgegeven aan setSharedProperty() . Het is dus geen referentie naar hetzelfde object (behalve in een aantal speciale gevallen). Specifieke details over de manier waarop gegevens worden gedeeld, staan beschreven in Gedeelde referenties en gekopieerde waarden .

Het gebruik van een gedeelde eigenschap om gegevens door te geven tussen workers heeft één groot voordeel: de eigenschap is al beschikbaar voordat de worker wordt uitgevoerd. Voordat een worker op de achtergrond wordt uitgevoerd, kan de methode setSharedProperty() van het Worker-object van de worker namelijk al worden aangeroepen om een gedeelde eigenschap in te stellen. Wanneer de bovenliggende worker de methode start() van de worker aanroept, roept de runtime de constructor aan van de hoofdklasse van de onderliggende worker. Alle gedeelde eigenschappen die zijn ingesteld voordat start() werd aangeroepen, zijn beschikbaar om te worden gelezen door de code in de onderliggende worker.

Gegevens doorgeven met een MessageChannel-object

Een MessageChannel-object biedt een methode om gegevens in één richting door te geven tussen twee workers. Het gebruik van een MessageChannel-object voor het doorgeven van gegevens biedt één groot voordeel. Wanneer u een bericht (een object) verzendt via een berichtenkanaal, wordt een channelMessage -gebeurtenis verzonden door het MessageChannel-object. De code in de ontvangende worker kan naar die gebeurtenis luisteren om erachter te komen wanneer er gegevens beschikbaar zijn. Op deze manier hoeft de ontvangende worker niet telkens te controleren of de gegevens zijn bijgewerkt.

Een berichtenkanaal vormt een koppeling tussen maximaal twee workers, een zender en een ontvanger. Als u een MessageChannel-object wilt maken, roept u de methode createMessageChannel() van het Worker-object van de verzendende worker aan. Hierbij geeft u de ontvangende worker door als argument:

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

Beide workers moeten toegang hebben tot het MessageChannel-object. De eenvoudigste manier om dit te bereiken is het MessageChannel-object doorgeven via de methode setSharedProperty() :

receivingWorker.setSharedProperty("incomingChannel", sendChannel);

In de ontvangende worker registreert u een listener voor de gebeurtenis channelMessage van het MessageChannel-object. Deze gebeurtenis wordt verzonden wanneer de verzendende worker gegevens verstuurt via het berichtenkanaal.

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

Als u ook daadwerkelijk gegevens wilt verzenden, roept u in de verzendende worker de methode send() van het MessageChannel-object aan:

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

In de ontvangende worker wordt de channelMessage -gebeurtenishandler aangeroepen door het MessageChannel-object. Vervolgens kan de ontvangende worker de gegevens ophalen door de methode receive() van het MessageChannel-object aan te roepen.

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

Het object dat door de receive-methode wordt geretourneerd is van hetzelfde gegevenstype als het object dat werd doorgegeven aan de send() -methode. Het ontvangen object is een kopie van het object dat werd doorgegeven door de verzendende worker. Het is dus geen referentie naar het object in de verzendende worker, tenzij het gaat om een van de weinige gegevenstypen die worden beschreven in Gedeelde referenties en gekopieerde waarden .

Gegevens delen met behulp van een deelbare ByteArray

Wanneer een object wordt doorgegeven tussen twee workers, krijgt de ontvangende worker een nieuw object welke een kopie is van het oorspronkelijke object. De twee objecten worden opgeslagen op verschillende locatie in het geheugen van het systeem. Als gevolg hiervan verhoogt elke kopie van het object dat wordt ontvangen, het totale geheugengebruik dat door de runtime wordt gebruikt. Bovendien hebben eventuele wijzigingen die u aanbrengt aan een object in een worker, geen invloed op de kopie in de andere worker. Zie Gedeelde referenties en gekopieerde waarden voor meer informatie over hoe gegevens worden gekopieerd.

Een ByteArray-object maakt standaard gebruik van hetzelfde gedrag. Als u een ByteArray-instantie doorgeeft aan de methode setSharedProperty() van een Worker-object of de methode send() van een MessageChannel-object, maakt de runtime een nieuwe ByteArray in het geheugen van de computer en krijgt de ontvangende worker een ByteArray-instantie een verwijzing is naar die nieuwe ByteArray. U kunt dit gedrag echter wijzigen voor een ByteArray-object door de eigenschap shareable van dit object in te stellen op true .

Als een deelbaar ByteArray-object wordt doorgegeven van de ene worker naar de andere, is de ByteArray-instantie in de ontvangende worker een verwijzing naar hetzelfde onderliggende besturingssysteemgeheugen dat door de ByteArray-instantie in de verzendende worker wordt gebruikt. Als de code in één worker de inhoud van de bytearray wijzigt, worden deze wijzigingen onmiddellijk beschikbaar in andere workers die toegang hebben tot diezelfde gedeelde array.

Omdat workers hun code tegelijk uitvoeren, is het mogelijk dat twee workers op hetzelfde moment toegang proberen te krijgen tot dezelfde bytes in een bytearray. Dit kan leiden tot verlies of beschadiging van gegevens. Er zijn verschillende API's die u kunt gebruiken om de toegang tot gedeelde bronnen te beheren en dergelijke problemen te voorkomen.

De ByteArray-klasse beschikt over methoden waarmee u de inhoud van de bytearray in één bewerking kunt valideren en wijzigen:

Bovendien bevat het flash.concurrent-pakket klassen die toegangsbeheer bieden wanneer er met gedeelde bronnen wordt gewerkt:

Gedeelde referenties en gekopieerde waarden

Als u Worker.setSharedProperty() of MessageChannel.send() aanroept, wordt het object dat wordt doorgegeven aan de ontvangende worker, normaal gesproken via serienummering omgezet in een AMF-indeling. Dit heeft een aantal consequenties:

  • Het object dat wordt gemaakt in de ontvangende worker wanneer de methode getSharedProperty() van die worker wordt aangeroepen, wordt via serienummering terug omgezet op basis van de AMF-bytes. Dit is een kopie van het oorspronkelijke object en geen referentie naar het object. Wijzigingen die worden doorgevoerd in het object van een van beide workers, worden niet doorgevoerd in de kopie van de andere worker.

  • Objecten die niet via serienummering kunnen worden omgezet in een AMF-indeling, zoals weergaveobjecten, kunnen niet worden doorgegeven aan een worker via Worker.setSharedProperty() of MessageChannel.send() .

  • Voor een juiste omzetting via serienummering van een aangepaste klasse moet de klassendefinitie worden geregistreerd met de functie flash.net.registerClassAlias() of met [RemoteClass] -metagegevens. Hetzelfde alias moet worden gebruikt voor de klassenversies in beide workers.

Er zijn vijf speciale gevallen van objecten die daadwerkelijk worden gedeeld en dus niet tussen workers worden gekopieerd:

  • Worker-objecten

  • MessageChannel-objecten

  • deelbare bytearray (een ByteArray-object waarvan de eigenschap shareable true is)

  • Mutex-objecten

  • Condition-objecten

Wanneer u een instantie van een van deze objecten doorgeeft met de methode Worker.setSharedProperty() of de methode MessageChannel.send() , beschikt elke worker over een referentie naar hetzelfde onderliggende object. Wijzigingen die in één worker worden toegepast op een instantie zijn dan direct beschikbaar in alle andere workers. Bovendien geldt dat als u eenzelfde instantie van een van deze objecten meerdere keren doorgeeft aan een worker, er niet telkens een nieuw exemplaar van het object in de ontvangende worker wordt gemaakt door de runtime. In plaats hiervan wordt dezelfde referentie opnieuw gebruikt.

Overige technieken voor gegevensdeling

Naast de technieken voor het doorgeven van gegevens die specifiek zijn voor workers, kunnen workers ook gegevens uitwisselen via een van de bestaande API's die ondersteuning bieden voor gegevensdeling tussen twee SWF-toepassingen, zoals de volgende:

  • lokale, gezamenlijke objecten

  • gegevens schrijven naar een bestand in één worker en het bestand lezen in een andere worker

  • gegevens opslaan naar en lezen van een SQLite-database

Wanneer een bron wordt gedeeld door twee of meer workers, moet u situaties vermijden waarin de bron gelijktijdig wordt benaderd door meerdere workers. Als een bestand op het lokale bestandssysteem gelijktijdig toegankelijk is voor meerdere workers, kan dat leiden tot gegevensverlies of -beschadiging. Een dergelijk proces wordt mogelijk ook niet ondersteund door het besturingssysteem.

Als beveiliging tegen problemen met gelijktijdige toegang, gebruikt u de Mutex- en Condition-klassen in het flash.concurrent-pakket om toegangsbeheer te bieden wanneer er met gedeelde bronnen wordt gewerkt.

In tegenstelling tot andere mechanismen voor gegevensdeling, is de SQLite-database-engine speciaal ontworpen voor gelijktijdige gegevenstoegang. De engine beschikt over een ingebouwde ondersteuningsfunctie voor transacties. Een SQLite-database is daarom zonder risico op gegevensverlies toegankelijk voor meerdere workers. Aangezien de workers verschillende SQLConnection-instanties gebruiken, krijgt elke worker via een afzonderlijke transactie toegang tot de database. Gelijktijdige bewerkingen voor gegevensmanipulatie zijn dan ook niet van invloed op de gegevensintegriteit.

Zie ook

Werken met lokale SQL-databases in AIR

flash.concurrent-pakket