El sistema de concurrencia de Swift proporciona soporte integrado para escribir código asíncrono y paralelo de forma estructurada. Para obtener una descripción detallada del sistema de concurrencia de Swift, consulte Tema de concurrencia del lenguaje de programación Swift.
Si bien las consideraciones de esta página se aplican en general al uso de realm con funciones de concurrencia de Swift, la versión 10.39.0 del SDK de Realm Swift permite usar Realm con actores de Swift. Puede usar Realm de forma aislada para un solo actor o con varios actores.
La compatibilidad con actores de Realm simplifica su uso en un contexto de actor principal y actor en segundo plano, y reemplaza gran parte de las recomendaciones de esta página sobre consideraciones de concurrencia. Para más información, consulte Usar Realm con actores - Swift SDK.
Advertencias sobre la concurrencia de Realm
A medida que implementa funciones de concurrencia en su aplicación, tenga en cuenta esta advertencia sobre el modelo de subprocesos de Realm y los comportamientos de subprocesos de concurrencia de Swift.
Suspender la ejecución con Await
En cualquier lugar donde utilice la palabra clave Swift await Marca un posible punto de suspensión en la ejecución de tu código. Con Swift 5.7, una vez que tu código se suspende, el código subsiguiente podría no ejecutarse en el mismo hilo. Esto significa que, en cualquier momento que uses await en tu código, el código subsiguiente podría ejecutarse en un hilo diferente al del código anterior o posterior.
Esto es intrínsecamente incompatible con el paradigma de objetos activos de Realm. Los objetos activos, las colecciones y las instancias Realm están confinados a un hilo: es decir, sólo son válidos en el hilo en el que se crearon. En la práctica, esto significa que no puedes pasar instancias en vivo a otros hilos. Sin embargo, Realm ofrece varios mecanismos para el uso compartido de objetos entre hilos. Estos mecanismos suelen requerir que tu código realice algún manejo explícito para transferir datos de forma segura entre hilos.
Puede utilizar algunos de estos mecanismos, como objetos congelados o la ThreadSafeReference, para utilizar de forma segura objetos Realm e instancias entre hilos utilizando la palabra clave await. También puedes evitar problemas relacionados con la ejecución simultánea marcando cualquier código asíncrono de Realm con @MainActor para garantizar que tus aplicaciones siempre ejecuten este código en el hilo principal.
Como regla general, tenga en cuenta que usar Realm en un await contexto sin incorporar protección de subprocesos puede generar un comportamiento incoherente. En ocasiones, el código puede funcionar correctamente. En otros casos, puede generar un error relacionado con la escritura en un subproceso incorrecto.
API asíncronas/en espera
Muchas API de Realm Swift que trabajan con una aplicación de Atlas App Services o un reino sincronizado son compatibles con la sintaxis async/await de Swift. Para ver ejemplos, consulte:
Si tiene solicitudes de funciones específicas relacionadas con las API async/await de Swift, consulte el motor de comentarios de MongoDB para Realm. El equipo del SDK de Swift de Realm planea seguir desarrollando funciones relacionadas con la concurrencia basándose en los comentarios de la comunidad y la evolución de la concurrencia en Swift.
Realizar escrituras en segundo plano
Un caso de uso comúnmente solicitado para el código asíncrono es realizar operaciones de guardar en segundo plano sin bloquear el hilo principal.
Realm tiene dos API que permiten realizar escrituras asincrónicas:
La API writeAsync() permite realizar escrituras asincrónicas utilizando controladores de finalización Swift.
La API asyncWrite() permite realizar escrituras asincrónicas utilizando la sintaxis async/await de Swift.
Ambas API le permiten agregar, actualizar o eliminar objetos en segundo plano sin utilizar objetos congelados ni pasar una referencia segura para subprocesos.
Con la API writeAsync(), la espera para obtener el bloqueo de escritura y la confirmación de una transacción se realizan en segundo plano. El bloque de escritura se ejecuta en el hilo que realiza la llamada. Esto proporciona seguridad para subprocesos sin necesidad de gestionar manualmente objetos congelados ni pasar referencias entre subprocesos.
Sin embargo, mientras se ejecuta el bloque de escritura, se bloquean nuevas transacciones en el hilo que realiza la llamada. Esto significa que una escritura grande con la API writeAsync() podría bloquear escrituras pequeñas y rápidas durante su ejecución.
La API asyncWrite() suspende la tarea que realiza la llamada mientras espera su turno para escribir, en lugar de bloquear el hilo. Además, la E/S para escribir datos en el disco la realiza un hilo de trabajo en segundo plano. Para escrituras pequeñas, usar esta función en el hilo principal puede bloquearlo durante menos tiempo que enviar manualmente la escritura a un hilo en segundo plano.
Para obtener más información, incluidos ejemplos de código, consulte: Realizar una escritura en segundo plano.
Tareas y grupos de tareas
La concurrencia de Swift proporciona API para gestionar tareas y grupos de tareas. La documentación de concurrencia de Swift define una tarea como una unidad de trabajo que puede ejecutarse asincrónicamente como parte de su programa. Tarea permite definir específicamente una unidad de trabajo asincrónico. Grupo de tareas permite definir un conjunto de tareas que se ejecutan como una unidad dentro del grupo de tareas principal.
Las tareas y los grupos de tareas permiten asignar el hilo a otras tareas importantes o cancelar una tarea de larga duración que podría bloquear otras operaciones. Para obtener estas ventajas, podrías considerar usar tareas y grupos de tareas para gestionar las escrituras en el dominio en segundo plano.
Sin embargo, las restricciones de hilo descritas en "Suspender la ejecución con Await" se aplican en el contexto de la tarea. Si la tarea contiene await puntos, el código posterior podría ejecutarse o reanudarse en un hilo diferente e infringir el confinamiento de hilo de Realm.
Debes anotar las funciones que ejecutas en un contexto de tarea con @MainActor para garantizar que el código que accede a Realm solo se ejecute en el hilo principal. Esto anula algunas de las ventajas de usar tareas y puede significar que no sea una buena opción de diseño para aplicaciones que usan Realm, a menos que las uses únicamente para actividades de red, como la gestión de usuarios.
Aislamiento del actor
Tip
Usar Realm con actores Swift
La información de esta sección se aplica a las versiones del SDK de Realm anteriores a la 10.39.0. A partir de la versión 10.39.0 del SDK de Realm Swift y posteriores, el SDK admite el uso de Realm con actores Swift y la funcionalidad asíncrona relacionada.
Para obtener más información, consulte Usar Realm con actores - Swift SDK.
El aislamiento de actores proporciona la percepción de limitar el acceso al Reino a un actor dedicado y, por lo tanto, parece una forma segura de gestionar el acceso al Reino en un contexto asincrónico.
Sin embargo, actualmente no se admite el uso de Realm en una función asíncrona que no sea@MainActor.
En Swift 5.6, esto solía funcionar por coincidencia. La ejecución después de un await continuaba en el hilo donde se ejecutaba el objeto esperado. Usar await Realm() en una función asíncrona hacía que el código posterior se ejecutara en el hilo principal hasta la siguiente llamada a una función aislada del actor.
Swift 5.7, en cambio, salta entre subprocesos al cambiar los contextos de aislamiento de los actores. Una función asíncrona no aislada siempre se ejecuta en un subproceso en segundo plano.
Si tienes código que utiliza await Realm() y funciona en la versión 5.6, marcar la función como @MainActor hará que funcione con Swift 5.7. Funcionará como lo hizo - sin querer - en 5.6.
Errores relacionados con el código de concurrencia
Con mayor frecuencia, el error que ve relacionado con el acceso a Realm a través del código de concurrencia es Realm accessed from incorrect thread.. Esto se debe a los problemas de aislamiento de subprocesos que se describen en esta página.
Para evitar problemas relacionados con el threading en el código que utiliza funcionalidades de concurrencia de Swift:
Actualice a una versión del SDK de Realm Swift que admita dominios aislados por actores y úsela como alternativa a la gestión manual de subprocesos. Para obtener más información, consulte Usar Realm con actores - SDK de Swift.
No cambie los contextos de ejecución al acceder a un dominio. Si abre un dominio en el hilo principal para proporcionar datos a su interfaz de usuario, anote con
@MainActorlas funciones posteriores donde acceda al dominio de forma asíncrona para garantizar que siempre se ejecuten en el hilo principal. Recuerde queawaitmarca un punto de suspensión que podría cambiar a otro hilo.Las aplicaciones que no usan dominios aislados por actores pueden usar la
writeAsyncAPI para realizar una escritura en segundo plano. Esto gestiona el acceso al dominio de forma segura para subprocesos, sin necesidad de escribir código especializado. Esta API especial externaliza aspectos del proceso de escritura (cuando es seguro hacerlo) para ejecutarse en un contexto asíncrono. A menos que escriba en un dominio aislado por actores, no utilice este método conasync/awaitla sintaxis de Swift. Úselo sincrónicamente en su código. Como alternativa, puede usar laasyncWriteAPI con la sintaxis de Swiftasync/awaital esperar escrituras en dominios asíncronos.Si desea escribir código concurrente explícito que no esté aislado de actores y donde el acceso a un reino se realice de forma segura para subprocesos, puede pasar instancias explícitamente entre subprocesos cuando corresponda para evitar fallos relacionados con los subprocesos. Esto requiere un buen conocimiento del modelo de subprocesos de Realm, así como la consideración de los comportamientos de subprocesos concurrentes de Swift.
Tipos enviables, no enviables y confinados a subprocesos
La API pública del SDK Swift de Realm contiene tipos que se dividen en tres categorías amplias:
Enviable
No se puede enviar y no está confinado en el hilo
Confinado en hilo
Puedes compartir tipos que no sean Enviables y que no estén confinados entre subprocesos, pero debes sincronizarlos.
Los tipos confinados por subprocesos, a menos que estén congelados, se limitan a un contexto de aislamiento. No se pueden pasar entre estos contextos, ni siquiera con sincronización.
Enviable | No enviable | Hilo confinado |
|---|---|---|
CualquierBSON | Configuración de RLMApp | AnyRealmCollection |
AsyncOpen | Opciones de búsqueda y modificación de RLM | AnyRealmValue |
Suscripción abierta asíncrona | Opciones de búsqueda de RLM | Lista |
Autorización de clave RLMAPI | Transporte en red RLM | Map |
Aplicación RLM | Solicitud RLM | MutableSet |
RLMAsyncOpenTask | Respuesta de RLMR | Proyección |
Flujo de cambio de RLM | Configuración de RLMSync | RLMArray |
Información de escritura compensatoria RLM | Opciones de tiempo de espera de sincronización de RLM | Flujo de cambio de RLM |
Credenciales de RLMC | Diccionario RLM | |
RLMDecimal128 | Cambio de diccionario RLM | |
RLMEmailPasswordAuth | Objeto RLMEmbedded | |
RLMMaxKey | Objetos de enlace RLM | |
RLMMinKey | Objeto RLM | |
Cliente RLMMongo | Cambio de propiedad RLM | |
Colección RLMMongo | RLMRealm | |
Base de datos RLMMongo | Resultados de RLM | |
ID de objeto RLM | RLMSection | |
Esquema de objeto RLM | Resultados seccionados de RLM | |
Notificación de progreso de RLM | Conjunto de cambios de resultados seccionados de RLM | |
Token de notificación de progreso de RLM | Conjunto RLM | |
Propiedad RLM | Suscripción a RLMSync | |
Descriptor de propiedad RLM | Conjunto de suscripciones de sincronización RLM | |
Cliente proveedor de RLM | Reino Opcional | |
Cliente RLMPush | Propiedad del reino | |
Esquema RLMSchema | ||
Descriptor de clasificación RLMSort | ||
Token de acción de error de sincronización RLM | ||
Administrador de sincronización RLM | ||
Sesión de sincronización RLM | ||
Referencia segura para subprocesos de RLM | ||
Resultado de actualización de RLM | ||
Usuario de RLMU | ||
RLMUserAPIKey | ||
Identidad de usuario de RLMU | ||
Perfil de usuario de RLMU | ||
ThreadSafe |