Los actores globales son una característica poderosa en Swift que te permite definir un contexto de ejecución específico para un conjunto de funciones o closures. En esencia, un actor global actúa como un “hilo virtual” donde todas las funciones anotadas con el nombre de ese actor global se ejecutarán. Esto garantiza que el código dentro de esas funciones se ejecute de manera secuencial y segura, evitando conflictos de datos y condiciones de carrera.
Ventajas de los actores globales
Coordinación centralizada: Los actores globales te permiten centralizar la gestión de la concurrencia en tu aplicación. En lugar de tener que preocuparte por la sincronización manual de hilos o el uso de bloqueos, puedes simplemente anotar las funciones relevantes con el nombre del actor global y Swift se encargará de ejecutarlas en el orden correcto.
Seguridad en entornos concurrentes: Al garantizar que el código anotado con el mismo actor global se ejecute en el mismo hilo, los actores globales eliminan la posibilidad de que múltiples hilos accedan a los mismos datos al mismo tiempo, lo que previene condiciones de carrera y otros problemas de concurrencia.
Flexibilidad: A diferencia de
@MainActor
, que restringe la ejecución al hilo principal, puedes crear tus propios actores globales personalizados para diferentes propósitos. Esto te brinda flexibilidad para organizar tu código concurrente de manera más efectiva y adaptar la gestión de la concurrencia a las necesidades específicas de tu aplicación.Legibilidad y mantenibilidad: El uso de actores globales hace que tu código sea más legible y fácil de mantener. Al ver una función anotada con un actor global, sabes inmediatamente en qué contexto se ejecutará y qué garantías de seguridad en entornos concurrentes puedes esperar.
Casos de uso comunes
Acceso a recursos compartidos: Si tienes recursos compartidos (como bases de datos, archivos o variables globales) a los que se accede desde diferentes partes de tu aplicación, un actor global puede garantizar que el acceso a estos recursos se realice de manera segura y ordenada.
Coordinación de actores: Si tienes múltiples actores en tu aplicación que necesitan interactuar entre sí, un actor global puede actuar como un punto central de coordinación para garantizar que estas interacciones ocurran de manera segura y sin conflictos.
Operaciones de larga duración: Si tienes operaciones de larga duración que no deseas ejecutar en el hilo principal para evitar bloquear la interfaz de usuario, puedes crear un actor global dedicado para ejecutar estas operaciones en segundo plano.
Consideraciones importantes
Granularidad: Es importante elegir la granularidad adecuada para tus actores globales. Si creas demasiados actores globales, podrías terminar con una sobrecarga de gestión de hilos. Por otro lado, si tienes muy pocos actores globales, podrías estar limitando la concurrencia potencial de tu aplicación.
Rendimiento: Aunque los actores globales ofrecen una forma conveniente de gestionar la concurrencia, es importante tener en cuenta que la coordinación de hilos puede tener un impacto en el rendimiento. Si tu aplicación es extremadamente sensible al rendimiento, es posible que debas considerar otras técnicas de concurrencia en algunos casos.
Ejemplo de uso de los actores globales:
@globalActor
actor Yor {
static let shared: Yor = Yor()
}
actor Actor {
private var text: String = ""
func setText(_ text: String) {
self.text = text
}
func getText() -> String {
return text
}
}
@Yor
class TestTests {
let actor: Actor = Actor()
func testExample() async {
await actor.setText("Hello World")
}
}
Descripción:
@globalActor actor Yor
: Esta línea define un actor global llamadoYor
. Los actores globales actúan como un punto central de coordinación para la ejecución de código. La propiedadshared
proporciona una instancia única deYor
a la que se puede acceder desde cualquier lugar de tu aplicación.actor Actor
: Este es un actor regular que encapsula una propiedad privadatext
y proporciona métodos para establecer y obtener su valor. Los actores garantizan que solo un hilo a la vez pueda acceder a sus propiedades, evitando así condiciones de carrera.@Yor class TestTests
: La claseTestTests
está anotada con@Yor
. Esto significa que todas las funciones y propiedades no-async dentro de esta clase se ejecutarán automáticamente en el contexto del actor globalYor
.func testExample() async
: Esta función esasync
, lo que significa que puede suspender su ejecución y esperar a que se completen las operaciones asincrónicas, como interactuar con otros actores.await actor.setText("Hello World")
: Dentro detestExample()
, usamosawait
para llamar al métodosetText
delactor
. Dado quetestExample()
se ejecuta en el contexto deYor
yactor
es un actor normal, Swift se asegura de que esta interacción ocurra de manera segura y sincronizada.
Implicación Práctica
Este patrón de diseño es especialmente útil cuando tienes múltiples actores en tu aplicación y necesitas coordinar su acceso desde diferentes clases o módulos. Al usar un actor global, puedes centralizar la gestión de la concurrencia y asegurarte de que las interacciones con los actores ocurran en un orden predecible y seguro.
En resumen:
- Los actores globales (
@globalActor
) ofrecen una forma elegante de organizar y coordinar el acceso a actores en aplicaciones Swift concurrentes. - Anotar una clase con el nombre de un actor global garantiza que sus métodos no-async se ejecuten en el contexto de ese actor.
- El uso de
await
al interactuar con actores desde funcionesasync
asegura la seguridad en entornos concurrentes y evita condiciones de carrera.
Conclusiones:
Los actores globales son una herramienta valiosa en el conjunto de herramientas de concurrencia de Swift. Te permiten escribir código concurrente seguro y bien organizado, facilitando el razonamiento sobre la interacción de diferentes partes de tu aplicación en un entorno multihilo. Si estás desarrollando aplicaciones Swift que involucran concurrencia, ¡definitivamente vale la pena explorar el uso de actores globales!
Gracias por leer. Si te ha parecido útil puedes dejarme un comentario. Feliz codificación!