Por que simultaneidade?
Assim que você adiciona tarefas pesadas ao seu aplicativo, como o carregamento de dados, ele retarda o trabalho da IU ou até o congela. A simultaneidade permite que você execute 2 ou mais tarefas “simultaneamente”. A desvantagem dessa abordagem é a segurança do thread, que nem sempre é tão fácil de controlar. Fe quando diferentes tarefas desejam acessar os mesmos recursos, como tentar alterar a mesma variável em diferentes threads ou acessar os recursos já bloqueados por diferentes threads.
Existem algumas abstrações das quais precisamos estar cientes.
- Filas
- Desempenho de tarefa síncrona / assíncrona.
- Prioridades.
- Problemas comuns.
Filas
Deve ser serial ou simultâneo . Bem como global ou privado ao mesmo tempo.
Com filas seriais, as tarefas serão concluídas uma a uma, enquanto com filas simultâneas, as tarefas serão realizadas simultaneamente e serão concluídas em agendamentos inesperados. O mesmo grupo de tarefas levará muito mais tempo em uma fila serial do que em uma fila simultânea.
Você pode criar suas próprias filas privadas ( seriais ou simultâneas ) ou usar filas globais (sistema) já disponíveis . A fila principal é a única fila serial de todas as filas globais .
É altamente recomendável não realizar tarefas pesadas que não sejam relacionadas ao trabalho da IU na fila principal (por exemplo, carregar dados da rede), mas sim realizá-las nas outras filas para manter a IU descongelada e responsiva às ações do usuário. Se permitirmos que a IU seja alterada nas outras filas, as alterações podem ser feitas em uma programação e velocidade diferentes e inesperadas. Alguns elementos da IU podem ser desenhados antes ou depois de serem necessários. Isso pode travar a IU. Também precisamos ter em mente que, como as filas globais são filas do sistema , algumas outras tarefas podem ser executadas pelo sistema nelas.
Qualidade de serviço / prioridade
As filas também têm diferentes qos (Quality of Service), que define a prioridade de execução da tarefa (da mais alta para a mais baixa aqui):
.userInteractive - fila principal
.userInitiated - para as tarefas iniciadas pelo usuário nas quais o usuário espera por alguma resposta
.utilidade - para as tarefas que leva algum tempo e não requer resposta imediata, por exemplo, trabalhar com dados
.background - para as tarefas que não estão relacionadas com a parte visual e que não são restritas para o tempo de conclusão).
Também existe uma fila
.default que não transfere as informações de qos . Se não foi possível detectar o qos oqos será usado entre .userInitiated e .utility .
As tarefas podem ser realizadas de forma síncrona ou assíncrona .
A função síncrona retorna o controle para a fila atual somente após a conclusão da tarefa. Ele bloqueia a fila e espera até que a tarefa seja concluída.
A função assíncrona retorna o controle para a fila atual logo após a tarefa ter sido enviada para ser executada na fila diferente. Não espera até que a tarefa seja concluída. Não bloqueia a fila.
Problemas comuns.
Os erros mais comuns que os programadores cometem ao projetar os aplicativos simultâneos são os seguintes:
- Condição de corrida - causada quando o aplicativo funciona depende da ordem de execução das partes do código.
- Inversão de prioridade - quando as tarefas de prioridade mais alta aguardam que as tarefas de prioridade menor sejam concluídas devido ao bloqueio de alguns recursos
- Deadlock - quando algumas filas têm espera infinita pelas fontes (variáveis, dados etc.) já bloqueadas por alguma dessas filas.
NUNCA chame a função de sincronização na fila principal .
Se você chamar a função de sincronização na fila principal, ela bloqueará a fila, assim como a fila ficará esperando a tarefa ser concluída, mas a tarefa nunca será concluída, pois não será possível nem mesmo iniciar devido à fila já bloqueado. É chamado de impasse .
Quando usar a sincronização?
Quando precisamos esperar até que a tarefa seja concluída. Veja quando estamos nos certificando de que alguma função / método não seja duplamente chamada. Sim, temos sincronização e estamos tentando evitar que seja duplamente chamado até que esteja completamente concluído. Aqui está um código para essa preocupação:
Como descobrir o que causou o relatório de falha de erro no dispositivo IOS?
DispatchQueue.main.sync
de um thread em segundo plano?