DEV Community

GoyesDev
GoyesDev

Posted on

[SC] Acceso aislado vs. no aislado en actores

Preguntas

¿Qué significa que los métodos de un actor estén aislados por defecto y cuál es la implicación práctica de esto?

El acceso a los datos del actor y a sus métodos se hace a través del executor serial del actor. Por esta razón hay que esperar para poder usar el executor desde fuera del dominio de aislamiento del actor (invocar con await).

¿Cuáles son los dos errores más comunes al trabajar con actores y cuál es su causa raíz?

  1. Tratar de leer una propiedad sin usar await (e.g. Actor-isolated property 'balance' can not be referenced from a non-isolated context)
  2. Tratar de invocar un método del actor sin usar await (e.g. Expression is 'async' but is not marked with 'await')

¿Por qué no se puede usar la palabra clave isolated directamente en la declaración de un método?

isolated se usa para acompañar un actor pasado como parámetro e indicar que método está aislado en ese actor.

isolated no marca un método sino un parámetro.

¿Cómo reduce el uso del parámetro isolated los puntos de suspensión innecesarios (await) en una función?

Como un método ya sabe apriori dentro de qué actor se está ejecutando, puede invocar otros métodos aislados en ese mismo actor.

¿Por qué solo se puede tener un parámetro isolated al mismo tiempo en una función?

El método no sabría en cuál de todos los actores pasados por parámetro está aislado.

¿Cómo funciona el patrón de transaction con un parámetro isolated dentro de un closure?

Desde fuera del método se define un closure que recibe el actor. El método se ejecuta de forma aislada dentro del actor, así que no es necesario volver a ejecutar el cuerpo del closure con await.

extension Actor {
  @discardableResult
  /// Agrega un método `perform` general para que cualquier actor acceda a su dominio de aislamiento y realice múltiples operaciones de una sola vez usando el closure.
  func performInIsolation<T: Sendable>(
    _ block: @Sendable (_ actor: isolated Self) throws -> T
  ) async rethrows -> T {
    try block(self)
    // Ejecutar performInIsolation requiere un await
    // Sin embargo, se ejecuta un closure al que se le pasa el actor
    // Todos los llamados que se hagan al actor dentro de este closure ya están aislados así que no se necesita await
  }
}
Enter fullscreen mode Exit fullscreen mode

En el código anterior se debe llamar performInIsolation con await. Esto significa que el cuerpo del método ya se ejecuta dentro del aislamiento del actor. Luego, el closure recibido por parámetro block no necesita volver a esperar cuando invoque métodos sobre actor.

¿En qué situaciones es apropiado usar nonisolated en un actor y qué riesgos elimina o introduce?

Cuando una propiedad o método no cambia nada el estado de un actor, se puede marcar con nonisolated. De esa forma, no hay que acceder a esto con await.

¿Cómo ayuda el compilador a prevenir errores cuando se accede a propiedades aisladas desde un contexto nonisolated?

Dentro de un método nonisolated no se puede modificar el estado mutable del actor. Saldrá el error: Actor-isolated property 'balance' can not be referenced from a nonisolated context.

¿Cuál es la diferencia práctica entre marcar una propiedad como nonisolated y simplemente acceder a ella con await?

No es necesario crear un punto de suspensión con await sino que se llama directamente el actor, sin cambiar al ejecutor del actor.

Recordar

Sin mirar el artículo, ¿puedes explicar con tus propias palabras cuándo usarías isolated y cuándo nonisolated?

¿Cuál es el ejemplo del BankAccount y qué ilustra sobre el aislamiento por defecto?

Revisión

¿Qué ventaja concreta ofrece performInIsolation frente a llamar métodos del actor individualmente con await?

¿Por qué el compilador no requiere marcar nonisolated una propiedad let pero sí una propiedad computada que accede a ella?

¿Cómo se relaciona el concepto de nonisolated con la conformancia a protocolos como CustomStringConvertible?


Bibliografía

Top comments (0)