Menu Docs
Página inicial do Docs
/ /
Atlas Device SDKs
/

Simultaneidade Swift - Swift SDK

Nesta página

  • Advertências sobre simultaneidade de Realm
  • Suspendendo a execução com Await
  • API assíncronas/de espera
  • Executar escrita em segundo plano
  • Tarefas e grupos de tarefas
  • Isolamento de atores
  • Erros relacionados ao código de simultaneidade
  • Tipos Enviáveis, Não Enviáveis e Confinados a Threads

O sistema de concorrência do Swift oferece suporte integrado para escrever código assíncrono e paralelo de forma estruturada. Para obter uma visão geral detalhada do sistema de concorrência do Swift , consulte o tópico Concorrência da linguagem de programação Swift .

Embora as considerações nesta página se apliquem amplamente ao uso do domínio com recursos de simultaneidade Swift, o domínio Swift SDK versão 10.39.0 adiciona suporte para o uso do domínio com Swift Actors. Você pode usar o Realm isolado para um único ator ou usar o Realm entre atores.

O suporte a atores da Realm simplifica o uso do Realm em um contexto de ator principal e de ator em segundo plano e substitui grande parte dos conselhos nesta página sobre considerações de simultaneidade. Para obter mais informações, consulte Usar Realm com atores - Swift SDK.

Ao implementar recursos de simultaneidade em seu aplicativo, considere esta ressalva sobre o modelo de threading do Realm e os comportamentos de threading de simultaneidade do Swift.

Em qualquer lugar que você use a palavra-chave Swift await marca um possível apontar de suspensão na execução do seu código. Com o Swift 5.7, assim que seu código for suspenso, o código subsequente poderá não ser executado na mesma thread. Isso significa que, em qualquer lugar que você use await em seu código, o código subsequente pode ser executado em uma thread diferente do código que o precede ou segue.

Isso é inerentemente incompatível com o paradigma de objetos vivos do Realm. Objetos ativos, coleções e instâncias de domínio são confinados na thread: ou seja, são válidos somente na thread em que foram criadas. De forma prática, isso significa que não é possível passar instâncias ativas para outras threads. No entanto, o Realm oferece vários mecanismos para compartilhar objetos entre threads. Esses mecanismos geralmente exigem que seu código faça algum tratamento explícito para passar dados com segurança entre threads.

Você pode usar alguns desses mecanismos, como objetos congelados ou o ThreadSafeReference, para usar com segurança objetos de Realm e instâncias em threads com a palavra-chave await. Você também pode evitar problemas relacionados ao threading marcando qualquer código de Realm assíncrono com @MainActor para garantir que suas aplicações sempre executem esse código no thread principal.

Como regra geral, lembre-se de que o uso do Realm em um contexto await sem incorporar a proteção de threading pode gerar um comportamento inconsistente. Às vezes, o código pode ser bem-sucedido. Em outros casos, ele pode gerar um erro relacionado à gravação em um thread incorreto.

Muitas API do Realm Swift que envolvem o trabalho com um aplicativo Atlas App Services ou um domínio sincronizado são compatíveis com a sintaxe async/await do Swift. Por exemplo, confira:

Se você tiver solicitações de recursos específicos relacionados às API async/await do Swift, consulte o mecanismo de feedback do MongoDB para Realm. A equipe do Swift SDK planeja continuar a desenvolver recursos relacionados à simultaneidade com base no feedback da comunidade e na evolução da simultaneidade do Swift.

Um caso de uso comumente solicitado para código assíncrono é executar operações de escrita em segundo plano sem bloquear a thread principal.

O Realm possui duas API que permitem realizar gravações assíncronas:

  • A API writeAsync() permite realizar gravações assíncronas usando manipuladores de conclusão Swift.

  • A API asyncWrite() permite executar gravações assíncronas usando a sintaxe Swift async/await.

Ambas as APIs permitem que você adicione, atualize ou exclua objetos em segundo plano sem usar objetos congelados ou passar uma referência segura de segmento.

Com a API writeAsync(), a espera para obter o bloqueio de gravação e a confirmação de uma transação ocorrem em segundo plano. O bloco de gravação em si é executado no tópico de chamada. Isso proporciona segurança de thread sem exigir que você manipule manualmente objetos congelados ou passe referências entre threads.

No entanto, embora o próprio bloco de gravação seja executado, isso bloqueia novas transações no tópico de chamada. Isso significa que uma gravação grande usando a API writeAsync() pode bloquear gravações pequenas e rápidas durante a execução.

A API do asyncWrite() suspende a tarefa de chamada enquanto espera a sua vez de escrever em vez de bloquear a conversa. Além disso, a E/S real para escrever dados em disco é feita por uma thread de trabalho em background. Para escritas pequenas, usar essa função na thread principal pode bloquear a thread principal por menos tempo do que encaminhar manualmente a escrita para uma thread em background.

Para obter mais informações, incluindo exemplos de código, consulte: Execute uma escrita em background.

A Swift Concurrency fornece APIs para gerenciar Tarefas e Grupos de tarefas. A documentação de concorrência rápida define uma tarefa como uma unidade de trabalho que pode ser executada de forma assíncrona como parte do seu programa. A tarefa permite definir especificamente uma unidade de trabalho assíncrono. O grupo de tarefas permite definir uma coleção de tarefas a serem executadas como uma unidade no grupo de tarefas pai.

Tarefas e grupos de tarefas oferecem a capacidade de transferir o thread para outros trabalhos importantes ou cancelar uma tarefa de longa duração que pode estar bloqueando outras operações. Para obter esses benefícios, você pode ficar tentado a usar Tarefas e Grupos de Tarefas para managed gravações no reino em segundo plano.

No entanto, as restrições de thread confinadas descritas em Suspendendo a execução com Await acima se aplicam no contexto Tarefa. Se sua Tarefa contiver await pontos, o código subsequente poderá ser executado ou retomado em uma thread diferente e violar o confinamento de thread do Realm.

Você deve anotar as funções que você executa em um contexto de tarefa com @MainActor para garantir que o código que acessa o Realm seja executado somente no thread principal. Isso nega alguns dos benefícios de usar Tarefas e pode média que essa não é uma boa opção de design para aplicativos que usam o Realm, a menos que você esteja usando Tarefas apenas para atividades de rede, como gerenciar usuários.

Dica

Veja também: Use Realm com Swift Actors

As informações nesta seção são aplicáveis às versões do Realm SDK anteriores à 10.39.0. A partir do Realm Swift SDK versão 10.39.0 e mais recente, o SDK oferece suporte ao uso do Realm com Swift Actors e à funcionalidade assíncrona relacionada.

Para obter mais informações, consulte Usar Realm com atores - Swift SDK.

O isolamento do ator fornece a percepção de confinar o acesso ao Realm a um ator dedicado e, portanto, parece uma maneira segura de manage o access ao Realm em um contexto asíncrono.

No entanto, o uso do Realm em uma função assíncrona que não seja@MainActor atualmente não é suportado.

No Swift 5.6, isso geralmente funcionava por coincidência. A execução após um await continuaria em qualquer thread em que o item esperado fosse executado. Usar await Realm() em uma função assíncrona resultaria na execução do código seguinte na thread principal até sua próxima chamada para uma função isolada do ator.

Em vez disso, o Swift 5.7 alterna as threads sempre que muda os contextos de isolamento do ator. Em vez disso, uma função assíncrona isolada sempre é executada em uma thread de fundo.

Se você tiver código que utiliza await Realm() e trabalha no 5.6, marcar a função como @MainActor fará com que ela funcione com Swift 5.7. Ele funcionará como funcionou - involuntariamente - no 5.6.

Na maioria das vezes, o erro que você vê relacionado ao acesso ao Realm por meio de código de concorrência é Realm accessed from incorrect thread. Isso se deve aos problemas de isolamento de thread descritos nesta página.

Para evitar problemas relacionados a segmentações em códigos que usam recursos de simultaneidade do Swift:

  • Atualize para uma versão do domínio Swift SDK que ofereça suporte a domínios isolados do ator e use isso como uma alternativa para gerenciar manualmente o threading. Para obter mais informações, consulte Usar Realm com atores - Swift SDK.

  • Não altere os contextos de execução ao acessar um Realm. Se você abrir um Realm na thread principal para fornecer dados para sua UI, anote as funções subsequentes onde você acessa o Realm de forma assíncrona com o @MainActor para garantir que ele sempre seja executado na thread principal. Lembre-se de que await marca um ponto de suspensão que pode mudar para uma thread diferente.

  • Os aplicativos que não usam domínios isolados por ator podem usar a API writeAsync para executar uma gravação em segundo plano. Isso gerencia o acesso ao domínio de maneira segura para threads, sem exigir que você escreva código especializado para fazer isso sozinho. Esta é uma API especial que terceiriza aspectos do processo de gravação - onde for seguro fazê-lo - para execução em um contexto assíncrono. A menos que você esteja gravando em um domínio isolado por ator, você não usa este método com a sintaxe async/await do Swift. Use este método de forma síncrona em seu código. Como alternativa, você pode usar a API asyncWrite com a sintaxe async/await do Swift ao aguardar gravações em regiões assíncronas.

  • Se quiser escrever explicitamente um código de simultaneidade que não seja isolado por atores, em que o acesso a um reino seja feito de forma segura para threads, você poderá passar explicitamente instâncias entre threads, quando aplicável, para evitar falhas relacionadas a threads. Isso requer um bom entendimento do modelo de threading do Realm, além de estar atento aos comportamentos de threading de simultaneidade do Swift.

A API pública do SDK do Realm Swift contém tipos que se enquadram em três categorias amplas:

  • Enviável

  • Não pode ser enviado e não está confinado a threads

  • Confinado por thread

Você pode compartilhar tipos que não são Sendable e que não são confinados por thread entre threads, mas deve sincronizá-los.

Os tipos confinados por thread, a menos que congelados, estão confinados a um contexto de isolamento. Você não pode passá-los entre esses contextos, mesmo com sincronização.

Enviável
Non-Sendable
Confinada à thread

AnyBSON

RLMAppConfiguration

AnyRealmCollection

AsyncOpen

RLMFindOneAndModifyOptions

AnyRealmValue

AsyncOpenSubscription

RLMFindOptions

Lista

RLMAPIKeyAuth

RLMNetworkTransport

Map

RLMApp

RLMRequest

MutableSet

RLMAsyncOpenTask

RLMResponse

Projeção

RLMChangeStream

RLMSyncConfiguration

RLMArray

RLMCompensatingWriteInfo

RLMSyncTimeoutOptions

RLMChangeStream

RLMCredentials

RLMDictionary

RLMDecimal128

RLMDictionaryChange

RLMEmailPasswordAuth

RLMEmbeddedObject

RLMMaxKey

RLMLinkingObjects

RLM Minkey

Objeto RLM

Cliente RLMMongoClient

RLMPropertyChange

RLMMongoCollection

RLMRealm

RLMMongoDatabase

RLMResults

RLMObjectId

RLMSection

RLMObjectSchema

RLMMongoClient

RLMProgressNotification

RLMSectionedResultsChangeset

RLMProgressNotificationToken

RLMSet

RLMProperty

RLMSyncSubscription

RLMPropertyDescriptor

RLMSyncSubscriptionSet

RLMProviderClient

RealmOptional

RLMPushClient

RealmProperty

RLMSchema

RLMSortDescriptor

RLMSyncErrorActionToken

RLMSyncManager

RLMSyncSession

RLMThreadSafeReference

RLMUpdateResult

RLMUser

RLMUserAPIKey

RLMUserIdentity

RLMUserProfile

ThreadSafe

Voltar

Use o Realm com Actors