Komunikacja między procesami roboczymi

Flash Player 11.4 i nowsze wersje, Adobe AIR 13.4 i nowsze wersje dla komputerów

Chociaż procesy robocze wykonują kod w oddzielnych wątkach wykonawczych, całkowita izolacja między wątkami oznaczałaby brak jakichkolwiek korzyści płynących z takiego rozwiązania. Komunikacja między procesami oznacza wzajemne przekazywanie danych. Są dostępne trzy podstawowe mechanizmy przekazywania danych między procesami roboczymi.

Wybierając metodę przekazywania danych odpowiednią w danej sytuacji, należy rozważyć dwa aspekty, w których te metody się różnią. Jedna różnica dotyczy tego, czy istnieje zdarzenie powodujące powiadomienie odbiorcy o dostępności nowych danych, czy odbierający proces roboczy musi sprawdzać dostępność aktualizacji. Inna różnica między tymi metodami udostępniania danych dotyczy samego sposobu przekazywania danych. W niektórych przypadkach odbierający proces roboczy otrzymuje kopię udostępnionych danych, co wymaga utworzenia większej liczby obiektów, a zatem większej ilości pamięci i liczby cykli procesora. W innych sytuacjach procesy robocze uzyskują dostęp do obiektów odnoszących się do tej samej podstawowej pamięci systemowej, co powoduje tworzenie mniejszej liczby obiektów i używanie mniejszej ilości pamięci. Te różnice opisano poniżej:

Metoda komunikacji

Wywołanie zdarzenia po otrzymaniu danych

Współużytkowanie pamięci między procesami roboczymi

Właściwości współużytkowane procesu roboczego

Nie.

Nie. Obiekty są kopiami, a nie odniesieniami.

MessageChannel

Tak

Nie. Obiekty są kopiami, a nie odniesieniami.

Współużytkowany obiekt ByteArray

Nie.

Tak. Pamięć jest współużytkowana.

Przekazywanie danych za pomocą właściwości współużytkowanej

Najprostszym sposobem na przekazywanie danych między procesami roboczymi jest użycie właściwości współużytkowanej. Każdy proces roboczy przechowuje wewnętrzny słownik wartości właściwości współużytkowanych. Właściwości te są zapisywane z nazwami w postaci kluczy typu String. Pozwala to na odróżnienie właściwości od siebie. Aby zapisać obiekt w procesie roboczym jako właściwość współużytkowaną, należy wywołać metodę procesu roboczego o nazwie setSharedProperty() i podać dwa argumenty — nazwę klucza oraz wartość do zapisania.

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

Wartość ustawionej właściwości współużytkowanej można odczytać, wywołując metodę getSharedProperty() procesu roboczego i przekazując nazwę klucza.

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

Nie istnieją żadne ograniczenia w zakresie tego, który proces roboczy może odczytywać lub ustawiać wartość współużytkowaną. Na przykład pewną wartość może zapisywać za pomocą metody setSharedProperty() proces roboczy działający w tle. Zapisaną wartość może odczytać proces macierzysty, używając metody getSharedProperty() .

Wartością przekazywaną do metody setSharedProperty() może być obiekt praktycznie dowolnego typu. Poza kilkoma specjalnymi sytuacjami po wywołaniu metody getSharedProperty() zwracanym obiektem jest kopia obiektu przekazanego w metodzie setSharedProperty() , a nie odniesienie do tego obiektu. Szczegółowe informacje na temat udostępniania danych zostały przedstawione w dokumencie Odniesienia współużytkowane i wartości kopiowane .

Największą zaletą właściwości współużytkowanych jest możliwość udostępnienia danych procesowi roboczemu, który nie został jeszcze uruchomiony. Wywołanie metody setSharedProperty() procesu roboczego działającego w tle i ustawienie właściwości współużytkowanej jest możliwe jeszcze przed uruchomieniem danego procesu. Gdy proces macierzysty wywołuje metodę start() procesu roboczego, środowisko wykonawcze wywołuje konstruktor klasy głównej procesu potomnego. Wszystkie właściwości współużytkowane ustawione przed wywołaniem metody start() są udostępniane kodowi potomnego procesu roboczego.

Przekazywanie danych za pomocą obiektu MessageChannel

Kanał komunikatów oferuje jednokierunkowe łącze do przekazywania danych między dwoma procesami roboczymi. Użycie obiektu MessageChannel do przesyłania danych ma jedną ważną zaletę. Wysłanie komunikatu (obiektu) za pomocą kanału wiadomości powoduje wywołanie zdarzenia channelMessage przez obiekt MessageChannel. Kod w odbierającym procesie roboczym może wykrywać to zdarzenie. Pozwala to określić moment udostępnienia danych. Dzięki temu odbierający proces roboczy nie musi ciągle sprawdzać, czy dane zostały zaktualizowane.

Kanał komunikatów jest powiązany z dwoma procesami roboczymi — nadającym i odbierającym. Aby utworzyć obiekt MessageChannel w procesie roboczym wysyłającym dane, należy wywołać metodę createMessageChannel() , podając proces roboczy będący odbiorcą.

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

Oba procesy robocze muszą mieć dostęp do obiektu MessageChannel. Najprostszym sposobem jest przekazanie obiektu MessageChannel za pomocą metody setSharedProperty() .

receivingWorker.setSharedProperty("incomingChannel", sendChannel);

W odbierającym procesie roboczym należy zarejestrować detektor zdarzeń channelMessage obiektu MessageChannel. Zdarzenie jest wysyłane, gdy wysyłający proces roboczy wysyła dane za pomocą kanału komunikatów.

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

Aby wysłać dane, w wysyłającym procesie roboczym należy wywołać metodę send() obiektu MessageChannel.

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

W odbierającym procesie roboczym obiekt MessageChannel wywołuje moduł obsługi zdarzeń channelMessage . Następnie, aby otrzymać dane, odbierający proces roboczy wywołuje metodę receive() obiektu MessageChannel.

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

Obiekt zwracany przez metodę odbierającą musi być tego samego typu, co obiekt przekazany do metody send() . Odbierany obiekt jest kopią obiektu przekazanego przez nadawcę, a nie odniesieniem do obiektu istniejącego u nadawcy. Nie dotyczy to kilku typów danych opisanych w rozdziale Odniesienia współużytkowane i wartości kopiowane .

Współużytkowanie danych za pomocą współużytkowanego obiektu ByteArray

W przypadku przekazywania obiektu między dwoma procesami roboczymi odbierający proces roboczy otrzymuje nowy obiekt stanowiący kopię obiektu oryginalnego. Te dwa obiekty znajdują się w różnych lokalizacjach w pamięci systemu. W związku z tym każda otrzymana kopia obiektu powoduje zwiększenie łącznej ilości pamięci używanej w środowisku wykonawczym. Ponadto zmiany wprowadzone w obiekcie w jednym procesie roboczym nie mają wpływu na jego kopię w innym procesie roboczym. Więcej informacji na temat kopiowania danych znajduje się w temacie Odniesienia współużytkowane i wartości kopiowane .

Domyślnie obiekt ByteArray używa tego samego schematu działania. Jeśli wystąpienie klasy ByteArray zostanie przekazane do metody setSharedProperty() obiektu Worker (procesu roboczego) lub do metody send() obiektu MessageChannel (kanału komunikatów), środowisko wykonawcze tworzy nowy obiekt ByteArray (tablicy bajtów) w pamięci komputera, a odbierający proces roboczy otrzymuje wystąpienie klasy ByteArray będące odniesieniem do tego nowego obiektu ByteArray. Można zmienić to zachowanie obiektu ByteArray, ustawiając dla jego właściwości shareable wartość true .

Kiedy współużytkowany obiekt ByteArray zostaje przekazany z jednego procesu roboczego do drugiego, wystąpienie klasy ByteArray w odbierającym procesie roboczym stanowi odniesienie do tej samej podstawowej pamięci systemu operacyjnego, która jest używana przez wystąpienie klasy ByteArray w wysyłającym procesie roboczym. Kiedy kod w jednym procesie roboczym zmienia zawartość tablicy bajtów, te zmiany są natychmiast dostępne w innych procesach roboczych mających dostęp do tej tablicy bajtów.

Procesy robocze wykonują swój kod jednocześnie, w związku z czym dwa procesy robocze mogą próbować jednocześnie uzyskać dostęp do tych samych bajtów w tablicy bajtów. Może to spowodować utratę lub uszkodzenie danych. Są dostępne interfejsy API umożliwiające zarządzanie dostępem do zasobów współużytkowanych i unikanie takich problemów.

Klasa ByteArray zawiera metody umożliwiające sprawdzanie poprawności i zmienianie zawartości tablicy bajtów w ramach jednej operacji:

Ponadto pakiet flash.concurrent zawiera klasy zapewniające kontrolę dostępu podczas pracy z zasobami współużytkowanymi:

Odniesienia współużytkowane i wartości kopiowane

W normalnej sytuacji po wywołaniu metody Worker.setSharedProperty() lub MessageChannel.send() obiekt jest serializowany w formacie AMF w celu przekazania do odbierającego procesu roboczego. Ma to kilka skutków:

  • Obiekt tworzony w odbierającym procesie roboczym po wywołaniu w nim metody getSharedProperty() jest deserializowany z formatu AMF. Jest to kopia oryginalnego obiektu, a nie odniesienie do niego. Zmiany wprowadzone w obiekcie w jednym procesie roboczym nie są automatycznie kopiowane do obiektu w drugim procesie.

  • Obiekty, których serializacja w formacie AMF nie jest możliwa — na przykład obiekty ekranowe — nie mogą być przekazywane do procesów roboczych przy użyciu metod Worker.setSharedProperty() i MessageChannel.send() .

  • Aby własna klasa została prawidłowo zdeserializowana, definicja klasy musi zostać zarejestrowana za pomocą metody flash.net.registerClassAlias() lub metadanych [RemoteClass] . Tego samego aliasu należy użyć dla obu wersji procesu roboczego klasy.

Istnieje pięć specjalnych typów obiektów, które są współużytkowane przez procesy robocze, a nie kopiowane między nimi:

  • Obiekty procesów roboczych

  • Obiekty MessageChannel

  • Współużytkowana tablica bajtów (obiekt ByteArray, którego właściwość shareable ma wartość true )

  • Obiekty Mutex

  • Obiekty Condition

Przekazanie wystąpienia jednego z tych obiektów za pomocą metody Worker.setSharedProperty() lub MessageChannel.send() powoduje, że każdy proces roboczy będzie mieć odniesienie do tego samego obiektu podstawowego. Zmiany wprowadzone w wystąpieniu w jednym procesie roboczym są natychmiast dostępne w innych procesach. Wielokrotne przekazanie tego samego wystąpienia jednego z tych obiektów do procesu roboczego nie oznacza tworzenia przez środowisko wykonawcze nowych kopii obiektu w odbierających procesach roboczych. Zamiast tego jest wielokrotnie używane to samo odniesienie.

Dodatkowe metody współużytkowania danych

Poza specyficznymi dla procesów roboczych mechanizmami przekazywania danych mogą one także wymieniać informacje za pomocą istniejących interfejsów API, które obsługują współużytkowanie danych między dwiema aplikacjami SWF. Niektóre dostępne opcje:

  • Lokalne obiekty współużytkowane

  • Zapisywanie danych do pliku w jednym procesie roboczym i odczytywanie w innym

  • Zapisywanie i odczytywanie danych za pomocą bazy danych SQLite

Podczas współużytkowania zasobu przez przynajmniej dwa procesy robocze należy unikać sytuacji, w której wiele procesów jednocześnie uzyskuje dostęp do danego zasobu. Na przykład jednoczesny dostęp do pliku w lokalnym systemie plików może spowodować utratę lub uszkodzenie danych lub nie być obsługiwany przez system operacyjny.

Problemów z jednoczesnym dostępem można uniknąć, używając klas Mutex i Condition zawartych w pakiecie flash.concurrent. Pozwalają one kontrolować dostęp do zasobów współużytkowanych.

W odróżnieniu do innych sposobów na współużytkowanie danych mechanizm bazy danych SQLite został skonstruowany z myślą o współbieżnym dostępie oraz oferuje wbudowaną obsługę transakcji. Dzięki temu bazy danych SQLite może używać jednocześnie wiele procesów roboczych bez ryzyka uszkodzenia danych. Procesy robocze używają różnych wystąpień klasy SQLConnection, dlatego każdy proces roboczy otwiera bazę danych w oddzielnej transakcji. Dzięki temu jednoczesna zmiana tych samych danych przez kilka procesów nie wpływa na ich spójność.

Zobacz także

Praca z lokalnymi bazami danych SQL w środowisku AIR

Pakiet flash.concurrent