Comunicación entre programas de trabajo

Flash Player 11.4 y versiones posteriores, Adobe AIR 13.4 y versiones posteriores para plataformas de escritorio

Aunque los programas de trabajo ejecutan su código en subprocesos de ejecución distintos, no supondrían ninguna ventaja si estuvieran totalmente aislados el uno del otro. La comunicación entre programas de trabajo en última instancia implica transferir datos entre programas de trabajo. Existen tres mecanismos principales para obtener datos entre programas de trabajo.

Al decidir qué técnicas de compartición de datos es la adecuada para una necesidad concreta de transferencia de datos, tenga en cuenta los dos importantes puntos que las diferencia. Una diferencia entre ambas reside en si hay un evento para notificar al receptor la disponibilidad de nuevos datos o si el programa de trabajo receptor debe buscar actualizaciones. Otra diferencia entre estas técnicas de compartición de datos está relacionada con el modo en que los datos se transfieren realmente. En algunos casos, el programa de trabajo receptor obtiene una copia de los datos compartidos, lo que significa que se han tenido que crear más objetos y se ha utilizado más memoria y ciclos de CPU. En otros casos, los programas de trabajo acceden a objetos que hacen referencia a la misma memoria subyacente del sistema, lo que implica una menor creación de objetos y menos uso de memoria en general. Estas diferencias se resumen a continuación:

Técnica de comunicación

Distribuye eventos al recibir datos

Comparte memoria con varios programas de trabajo

Propiedades compartidas del programa de trabajo

No

No, los objetos son copias, no referencias

MessageChannel

No, los objetos son copias, no referencias

ByteArray compartible

No

Sí, la memoria se comparte

Transferencia de datos con una propiedad compartida

La forma más básica de compartir datos entre programas de trabajo es usar una propiedad compartida. Cada programa de trabajo mantiene un diccionario interno con valores de propiedades compartidas. Las propiedades se almacenan con nombres de clave de cadena para distinguirlos de las propiedades. Para almacenar un objeto en un programa de trabajo como una propiedad compartida, llame al método setSharedProperty() del objeto Worker con dos argumentos, el nombre de la clave y el valor que se quiere almacenar:

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

Una vez definida la propiedad compartida, el valor se puede leer llamando al método getSharedProperty() del objeto Worker y transfiriendo el nombre de la clave:

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

No hay restricciones respecto a qué programa de trabajo lee o establece el valor de la propiedad. Por ejemplo, el código de un programa de trabajo en segundo plano puede llamar a su método setSharedProperty() para almacenar un valor. El código que se ejecuta en el programa de trabajo principal puede utilizar a continuación el método getSharedProperty() para recibir los datos.

El valor transferido al método setSharedProperty() puede ser prácticamente cualquier tipo de objeto. Cuando se llama al método getSharedProperty() , el objeto que se devuelve es una copia del objeto transferido al método setSharedProperty() y no una referencia al mismo objeto, salvo en algunos casos excepcionales. La información específica sobre el modo en que se comparten los datos se detalla en Referencias compartidas y valores copiados .

La mayor ventaja de usar una propiedad compartida para transferir datos entre programas de trabajo es que está disponible incluso antes de que el programa de trabajo empiece a ejecutarse. Puede llamar al método setSharedProperty() de un objeto Worker en segundo plano para establecer una propiedad incluso antes de que el programa de trabajo se esté ejecutando. Cuando el programa de trabajo principal llama al método start() del objeto Worker, el motor de ejecución llama al constructor de la clase principal del programa de trabajo secundario. Cualquier propiedad compartida establecida antes de llamar a start() estará disponible para que el código del programa de trabajo secundario pueda leerla.

Transferencia de datos con un objeto MessageChannel

Un canal de mensajes proporciona un vínculo unidireccional de transferencia de datos entre dos programas de trabajo. Usar un objeto MessageChannel para transferir datos entre programas de trabajo tiene una ventaja clave. Cuando se envía un mensaje (un objeto) a través de un canal de mensajes, el objeto MessageChannel distribuye un evento channelMessage . El código del programa de trabajo receptor puede detectar un evento para saber cuándo están disponibles los datos. De este modo, el programa de trabajo receptor no necesita estar comprobando actualizaciones de datos continuamente.

Un canal de mensajes está asociado solamente a dos programas de trabajo: uno receptor y uno emisor. Para crear un objeto MessageChannel, llame al método createMessageChannel() del objeto Worker y transfiera el programa de trabajo receptor como un argumento:

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

Ambos programas de trabajo necesitan tener acceso al objeto MessageChannel. El modo más sencillo de lograrlo es transferir el objeto MessageChannel mediante el método setSharedProperty() :

receivingWorker.setSharedProperty("incomingChannel", sendChannel);

En el programa de trabajo receptor, registre un detector para el evento channelMessage del objeto MessageChannel. El evento se distribuye cuando el programa de trabajo emisor envía datos a través del canal de mensajes.

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

Para enviar los datos, en el programa de trabajo emisor llame al método send() del objeto MessageChannel:

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

En el programa de trabajo receptor, el objeto MessageChannel llama al controlador de eventos channelMessage . El programa de trabajo receptor entonces puede obtener datos mediante una llamada al método receive() del objeto MessageChannel.

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

El objeto devuelto por el método receptor tiene el mismo tipo de datos que el objeto transferido al método send() . El objeto recibido es una copia del objeto transferido por el emisor, y no una referencia al objeto en el programa de trabajo emisor a no ser que sea uno de los pocos tipos de datos excepcionales que se describen en Referencias compartidas y valores copiados .

Compartir datos con un objeto ByteArray compartible

Cuando un objeto se transfiere entre dos programas de trabajo, el programa de trabajo receptor obtiene un nuevo objeto que es una copia del original. Los dos objetos se almacenan en distintas ubicaciones de la memoria del sistema. En consecuencia, cada copia del objeto que se recibe aumenta el uso total de memoria utilizada por el motor de ejecución. Además, cualquier cambio realizado en un objeto del programa de trabajo no afectará a la copia en el otro programa de trabajo. Para obtener más información sobre el modo en que se copian los datos, consulte Referencias compartidas y valores copiados .

De forma predeterminada, un objeto ByteArray se comporta de forma similar. Si transfiere una instancia de ByteArray a un método setSharedProperty() de un objeto Worker o un método send() de un objeto MessageChannel, el motor de ejecución crea un nuevo objeto ByteArray en la memoria del equipo y el programa de trabajo receptor obtiene una instancia de ByteArray que es una referencia a dicho nuevo objeto ByteArray. No obstante, puede cambiar este comportamiento del objeto ByteArray si establece su propiedad shareable en true .

Cuando un objeto ByteArray compartible se transfiere de un programa de trabajo a otro, la instancia de ByteArray del programa de trabajo es una referencia a la misma memoria subyacente del sistema operativo que utiliza la instancia de ByteArray del programa de trabajo emisor. Cuando el código de un programa de trabajo cambia el contenido del conjunto de bytes, dichos cambios están disponibles inmediatamente en los demás programas de trabajo que tengan acceso a dicho conjunto de bytes compartido.

Como los programas de trabajo ejecutan su código de forma simultánea, es posible que dos programas de trabajo intenten acceder al mismo tiempo a los mismos bytes de un conjunto de bytes. Esto podría provocar la pérdida o deterioro de los datos. Existen distintas API que puede utilizar para gestionar el acceso a recursos compartidos y evitar así estos problemas.

La clase ByteArray tiene métodos que permiten validar y modificar el contenido del conjunto de bytes en una única operación:

Además, el paquete flash.concurrent contiene clases que proporcionan control de acceso al trabajo con recursos compartidos:

Referencias compartidas y valores copiados

En un caso normal, cuando se llama a los métodos Worker.setSharedProperty() o MessageChannel.send() , el objeto que se transfiere al programa de trabajo receptor se transfiere mediante su serialización en formato AMF. Esto tiene algunas consecuencias:

  • El objeto creado en el programa de trabajo receptor cuando se llama al método getSharedProperty() se deserializa desde los bytes de AMF. Es una copia del objeto original, no una referencia al objeto. Cualquier cambio realizado en el objeto en cualquier programa de trabajo no se aplica a la copia en el otro programa de trabajo.

  • Los objetos que no se pueden serializar en formato AMF (por ejemplo, objetos de visualización) no se pueden transferir a un programa de trabajo con Worker.setSharedProperty() o MessageChannel.send() .

  • Para que una clase personalizada se pueda deserializar correctamente, la definición de la clase debe registrarse con la función flash.net.registerClassAlias() o los metadatos [RemoteClass] . Se debe utilizar el mismo alias para las dos versiones del programa de trabajo de la clase.

Existen cinco casos especiales de objetos que se comparten realmente, y que no se copian entre los programas de trabajo:

  • Objetos Worker

  • Objetos MessageChannel

  • conjunto de bytes compartible (un objeto ByteArray cuya propiedad shareable es true )

  • Objetos Mutex

  • Objetos Condition

Cuando se transfiere una instancia de uno de estos objetos con los métodos Worker.setSharedProperty() o MessageChannel.send() , cada programa de trabajo tiene una referencia al mismo objeto subyacente. Los cambios realizados en la instancia de un programa de trabajo estarán disponibles inmediatamente en los demás programas de trabajo. Además, si transfiere la misma instancia de estos objetos más de una vez a un programa de trabajo, el motor de ejecución no creará una copia nueva del objeto en el programa de trabajo receptor. En su lugar, se reutilizará la misma referencia.

Técnicas adicionales de compartición de datos

Además de los mecanismos específicos de programas de trabajo para transferir datos, los programas de trabajo también pueden intercambiar datos mediante cualquiera de las API existentes que admiten compartición de datos entre dos aplicaciones swf, por ejemplo:

  • objetos compartidos locales

  • escribir datos en un archivo de un programa de trabajo y leer desde el archivo de otro programa de trabajo

  • almacenar datos y leerlos en una base de datos de SQLite

Cuando se comparte un recurso entre dos o más programas de trabajo, generalmente es necesario evitar tener varios programas de trabajo que puedan acceder al recurso al mismo tiempo. Por ejemplo, si varios programas de trabajo acceden a un archivo del sistema de archivos local, podría causar pérdidas de datos o dañarlos, y podría no ser compatible con el sistema operativo.

Para evitar problemas de acceso simultáneo, utilice las clases Mutex y Condition del paquete flash.concurrent para proporcionar control de acceso al trabajo con recursos compartidos.

Al contrario de lo que sucede en otros mecanismos de compartición de datos, el motor de bases de datos de SQLite está diseñado para accesos simultáneos y tiene su propio soporte de transacciones integrado. Varios programas de trabajo pueden acceder a una base de datos de SQLite sin riesgo de dañar los datos. Dado que los programas de trabajo utilizan distintas instancias de SQLConnection, cada programa de trabajo accede a la base de datos en una transacción diferente. Las operaciones simultáneas de manipulación de datos no afectan a la integridad de los datos.

Véase también

Trabajo con bases de datos SQL locales en AIR

Paquete flash.concurrent