Comprensión durante la lectura
¿Qué es un "punto de suspensión" y por qué no siempre ocurre cuando usamos await?
Un "punto de suspensión" es un lugar donde ocurre un cambio de dominio de aislamiento. Al usar await, aparece un POSIBLE punto de suspensión, lo que significa que puede o no haber el cambio. Si el dominio de aislamiento de destino coincide con el de origen, entonces no hay suspensión.
¿Por qué es problemático tener mucho código entre dos puntos de suspensión?
Podríamos tener potenciales:
- "actor reentrancy"
- estado inconsciente
- saltos entre hilos
- deterioro en el desempeño de la app
¿Cuáles son las principales técnicas para controlar o reducir los puntos de suspensión en Swift Concurrency?
El principio detrás de todas las técnicas es:
- Hacer tanto trabajo síncrono como se pueda, antes de la suspensión
- Saltar al otro dominio, solo una vez.
- Terminar la tarea.
- Solo volver a saltar si es estrictamente necesario
Las técnicas son:
-
Usar métodos síncronos mientras sea posible: Si tenemos dos métodos
f1() asyncyf2() async, dondef2()es privado e invocado desdef1(). En este caso, sif2()puede ser síncrono, es mejor quitar elasync. - Tratar de evitar el "actor-reentrancy": Saliendo del actor cuando ya se hizo todo el trabajo que involucraba su estado.
-
Usar
nonisolated(nonsending)y@concurrent: Los métodosnonisolated(nonsending)herendan el dominio de aislamiento del invocador así que no hay punto de suspensión.@concurrentfuerza la ejecución en otro dominio de aislamiento. -
Heredar el actor con
#isolation: Si se hereda el dominio de aislamiento, no hay punto de suspensión. -
Preferir APIs que no suspenden: por ejemplo, usar
Task.isCancelleden lugar detry await Task.checkCancellation(). - Usar APIs paralelas para reducir el tiempo de ejecución.
¿Qué ventajas concretas ofrece usar métodos sincrónicos en lugar de marcar todo con async?
Si ya se está en un dominio de aislamiento diferente de MainActor y se puede vivir con bloquear el hilo (ejecución asíncrona), entonces es mejor no poner otro punto de suspensión.
De esta forma:
- No hay actor reentrancy.
- No hay saltos inesperados entre executors.
- El estado del actor es consistente durante el método.
- No hay puntos de suspensión ocultos.
¿Qué es el actor reentrancy y cómo se puede evitar restructurando el código?
Ante un punto de suspensión, puede haber un cambio de dominio de aislamiento. Aquí, en lugar de bloquear el hilo, el actor tiene permitido tomar alguna otra tarea mientras que la primera está suspendida. Esto se conoce como "interleaving" o solapamiento.
El "actor reentrancy" ocurre cuando, debido al "interleaving" una segunda tarea modifica el estado de una primera tarea, que inicialmente había sido suspendida.
El problema se resume en que el estado del actor podría cambiar entre dos líneas de código si hay un await de por medio.
Se puede evitar haciendo todo el trabajo que modifica el estado, y poniendo el punto de suspensión al final.
¿Cómo funciona nonisolated(nonsending) y en qué situaciones evita un punto de suspensión?
nonisolated(nonsending) sirve para heredar el dominio de aislamiento el método invocador. Sirve para evitar poner un punto de suspensión siempre y cuando no sea inconveniente bloquear el hilo en cuestión.
Si lo es, entonces se debe hacer que el tipo de dato transferido sea Sendable.
¿En qué se diferencian Task.isCancelled y Task.checkCancellation() respecto a la suspensión?
Task.isCancelled no suspende, mientras que Task.checkCancellation() puede hacerlo. Se prefiere el primer método sobre el segundo, siempre que no sea necesario arrojar un error cuando se detecte la cancelación.
Top comments (0)