Swift Concurrency Series 05 | La diferencia entre Actor y los métodos tradicionales de escritura segura para subprocesos
Los actores no son "cerraduras rápidas". Lo que realmente cambian es cómo se organiza el Estado compartido.
Cuando escuche Actor por primera vez, inconscientemente lo entenderá como “una herramienta de seguridad para subprocesos proporcionada por Swift”.
Esta comprensión no es del todo incorrecta, pero si se detiene aquí, será fácil escribir código que “use actores, pero la estructura aún es desordenada”.
Porque lo más importante de Actor es que cambia la idea predeterminada:
El estado mutable compartido no debe exponerse a todos primero y luego buscar formas de protegerlo; un enfoque más razonable es aislarlo primero y luego decidir cómo acceder a él desde el exterior.
Esto puede parecer una diferencia en la redacción, pero en realidad es un hito en los hábitos de diseño concurrente.
1. Lo más peligroso en la concurrencia suele ser el estado mutable compartido
La mayoría de los errores de concurrencia comienzan con:
- Dos tareas leen y escriben el mismo caché al mismo tiempo
- Una tarea aún no se ha escrito y otra tarea ya ha emitido un juicio basado en el valor anterior.
- Varias páginas modifican un estado global al mismo tiempo
- Un determinado servicio es responsable de actualizar los tokens, consumirlos y transmitir los resultados.
Estos problemas pueden parecer presentarse de muchas formas, pero las causas fundamentales suelen ser las mismas: **El estado mutable compartido no tiene límites claros. **
Una vez que los límites estatales no están claros, cualquier cambio en el orden de programación de tareas puede amplificar los errores.
2. El problema con las soluciones tradicionales de seguridad de subprocesos es que no están lo suficientemente centralizadas.
Las soluciones que utilizamos comúnmente en el pasado incluyen:
NSLock- cola en serie
- bloqueo de lectura y escritura
- Acuerdo del equipo de que “solo se puede acceder a este objeto en una cola determinada”
Ninguna de estas soluciones es incorrecta y muchos sistemas maduros todavía se utilizan de manera estable en la actualidad. Su verdadero problema es:
**Las reglas de acceso se encuentran fácilmente dispersas. **
Al principio quizás todavía recuerdes:
- Se debe acceder a este caché con un candado.
- Ese diccionario sólo se puede cambiar en la cola serial
- Un determinado estado solo se puede leer y escribir en el hilo principal
Pero a medida que aumente el número de puntos de llamada, estas reglas se irán distorsionando poco a poco. Lo más molesto de los errores de concurrencia es que a menudo ya no es posible garantizar que todo el equipo cumpla estrictamente esas reglas dispersas.
3. La idea central de Actor es “reducir el intercambio primero”
Este es el punto más importante que vale la pena repetir.
La idea tradicional es más como:
- Primero tener un estado compartido
- Luego piense en formas de protegerlo mediante bloqueos, colas y convenciones.
La idea del actor está más cerca:
- No se debe acceder a este estado de forma arbitraria.
- Primero lo puse en el límite de aislamiento.
- El mundo exterior sólo puede interactuar con él a través de la interfaz controlada.
El mayor cambio que esto trae es que nos vemos obligados a pensar en la propiedad del estatus, en lugar de aceptar que todos puedan tocarlo directamente.
Por ejemplo, si un coordinador de actualización de tokens es solo un objeto global con un montón de bloqueos, la mentalidad predeterminada es “Todos están usando este estado y tengo que protegerlo”.
Si es Actor, la mentalidad predeterminada será “Este estado es administrado por él y otros solo pueden solicitarle resultados o enviar comandos”.
Así cambia el diseño.
4. Este enfoque de aislamiento es más adecuado para proyectos complejos.
Porque lo que más temen los proyectos complejos es la proliferación de reglas.
Una vez que Actor bloquea el acceso al estado, se expondrán muchos problemas anteriormente:
-¿Quién controla estos datos?
- ¿El requisito externo es una instantánea, un valor derivado o una operación imperativa?
- Qué operaciones deben tener semántica serial y cuáles son solo consultas de solo lectura.
Estos problemas a menudo se retrasaban en el modelo anterior, porque todos por defecto “compartir primero y luego bloquear si hay problemas”. Los actores, por otro lado, fuerzan el diseño de límites antes.
Por lo tanto, prefiero pensar en Actor como una herramienta de diseño de concurrencia en lugar de simplemente una herramienta de seguridad de subprocesos.
5. ¿Cuál es el mejor lugar para colocar al Actor?
No todos los objetos son dignos de convertirse en Actores. Es más adecuado para roles que cumplan al mismo tiempo las siguientes características:
- Tener estado mutable compartido
- Se accederá simultáneamente por múltiples tareas
- La consistencia es importante
- Los métodos de acceso deben coordinarse de forma centralizada.
Los ejemplos típicos incluyen:
- Coordinador de caché de imágenes.
- Coordinador de actualización de tokens
- Descargar centro de registro de tareas
- Algún tipo de acceso a recursos globales.
- Centro de mensajes que requiere consumo en serie de eventos.
Lo que estos objetos tienen en común es que son centros estatales que se comparten entre tareas y son propensos a problemas de concurrencia.
Si es solo un servicio de función pura o un objeto de estado que solo se usa brevemente dentro de una sola página, es posible que no se necesite un actor.
6. ¿Cuál es la diferencia esencial entre Actor y “Agregar un candado a toda la clase”?
En la superficie, todos pueden realizar “múltiples tareas sin cambiar el estado”. Pero la experiencia en ingeniería varía mucho.
Al bloquear una clase completa, las preguntas comunes son:
- La persona que llama aún puede obtener muchos detalles internos.
- La granularidad de las cerraduras puede salirse de control fácilmente
- Algunos métodos llaman a otros recursos de sincronización, formando anidamientos complejos.
- Los miembros del equipo aún pueden eludir las reglas y acceder directamente a estados a los que no deberían acceder.
Actor, al menos a nivel semántico, expresa claramente:
- Este estado no se comparte libremente
- El acceso de aislamiento cruzado debe pasar explícitamente a través del límite asincrónico
- Acceder a este estado es en sí mismo un comportamiento restringido.
En otras palabras, los actores no sólo “ayudan a agregar protección”, sino que también hacen que los métodos de acceso inseguros sean más difíciles de escribir de manera informal.
7. El actor no puede resolver nada.
Esto debe quedar claro. Cuando aprenda este contenido por primera vez, tendrá la ilusión de que la seguridad de los hilos quedará en sus manos en el futuro.
De hecho, los actores solo resuelven un tipo de problema: aislar el estado compartido.
No resuelve:
- ¿Es razonable la secuencia empresarial en sí?
- ¿Deberían continuar las tareas antiguas después de abandonar la página?
- Si el resultado ha caducado
- ¿Está mal trazada la frontera estatal?
Por ejemplo, si la caché de resultados de búsqueda se convierte en un actor, pero la página aún permite que solicitudes antiguas sobrescriban nuevos resultados de palabras clave, el error seguirá existiendo. Porque el problema aquí es que, en primer lugar, la “validez de los resultados” no se modela.
Entonces los actores son importantes, pero no son una panacea para la concurrencia.
8. Las dos direcciones de Actor que más fácilmente se abusan
1. Intenta encajar todo en el Actor
Una vez que se considere que los actores tienen la etiqueta “más seguros siempre que se utilicen”, comenzarán a empaquetar demasiado:
- El estado que obviamente solo se usa en un contexto de un solo subproceso también está empaquetado como Actor
- La lógica que obviamente es más adecuada para el procesamiento de funciones puras también se fuerza en Actor
- Al final, todo el sistema está lleno de límites de acceso asincrónicos y la estructura se vuelve más pesada.
Más actores no siempre es mejor. La clave es ubicarlos donde realmente sea necesario aislar el estado compartido.
2. Trate a los actores como “prueba de seguridad”
Una vez que se agregan actores a algún código, el equipo asumirá que este fragmento de código es “seguro para subprocesos”. Pero muchos errores provienen de:
- Diseño incorrecto del ciclo de vida.
- Flujo de estado incorrecto
- Relación de tarea incorrecta
El actor puede garantizar “No te metas con la concurrencia y toques mi estado interno”, pero no puede garantizar “el proceso de negocio es correcto”.
9. Una pregunta de juicio más práctica
Si tiene dudas sobre si un objeto debe diseñarse como Actor, le sugiero que no pregunte primero “¿Será inseguro para subprocesos?”, sino que primero pregunte:
- ¿Tiene un importante estado mutable compartido en su interior?
- ¿Se accederá a este estado mediante varias tareas al mismo tiempo?
- ¿Quiero que el mundo exterior interactúe con él sólo a través de interfaces controladas?
- Si no se agrega el límite de aislamiento, ¿será fácil para el equipo hacer un mal uso de él en el futuro?
Si la respuesta a la mayoría de estas preguntas es “sí”, entonces probablemente sea una buena opción para el actor.
10. Conclusión: El valor real de Actor es cambiar el estado mutable compartido de la exposición predeterminada al aislamiento predeterminado.
Para decirlo en forma más breve, diría:
ActorLo que realmente ha cambiado es que “el estado mutable compartido finalmente ya no está expuesto a todos de forma predeterminada”.
El pensamiento tradicional es más bien: compartir primero, luego proteger. La idea de Actor es: aislar primero y luego decidir cómo acceder.
En sistemas concurrentes complejos, este cambio de pensamiento suele ser más importante que “una herramienta de seguridad de subprocesos más”.
What to read next
Want more posts about Swift Concurrency?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #Swift Concurrency?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home