Introdução à Concorrência e Multithreading em Swift
\n\nAplicativos móveis e desktop modernos precisam ser rápidos e responsivos. No desenvolvimento para iOS e macOS, o gerenciamento adequado de concorrência e multithreading desempenha um papel fundamental. O Swift oferece ferramentas poderosas para execução paralela de tarefas, desde o clássico Grand Central Dispatch (GCD) até o modelo moderno de async/await e atores.
\n\nNeste artigo, abordaremos todas as principais abordagens para trabalhar com threads em Swift: desde conceitos básicos até técnicas avançadas. Você aprenderá como evitar race conditions, deadlocks e outros problemas típicos da programação multithread.
\n\nGrand Central Dispatch (GCD) — O Clássico do Multithreading
\n\nGrand Central Dispatch (GCD) é uma biblioteca de baixo nível da Apple para gerenciar a execução paralela de código. Ela utiliza filas (dispatch queues) para distribuir tarefas entre threads.
\n\nTipos Principais de Filas
\n\nNo GCD, existem dois tipos principais de filas:
\n\n- \n
- Serial queues (sequenciais): as tarefas são executadas uma após a outra na ordem de adição. Ideais para sincronizar o acesso a recursos. \n
- Concurrent queues (paralelas): as tarefas podem ser executadas simultaneamente, sem garantia de ordem de conclusão. \n
Exemplo de Trabalho com GCD
\n\nimport Foundation\n\n// Criando uma fila serial\nlet serialQueue = DispatchQueue(label: "com.example.serial")\n\n// Criando uma fila paralela\nlet concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)\n\n// Execução assíncrona\nserialQueue.async {\n print("Tarefa 1 sendo executada em segundo plano")\n}\n\n// Execução síncrona (bloqueia a thread atual)\nserialQueue.sync {\n print("Tarefa 2 sendo executada de forma síncrona")\n}\n\n// Trabalhando com a thread principal\nDispatchQueue.main.async {\n print("Atualizando a UI na thread principal")\n}\n\n// Atraso na execução\nDispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {\n print("Executado após 2 segundos")\n}\n\nDispatch Group — Sincronização de Grupo de Tarefas
\n\nO Dispatch Group permite monitorar a conclusão de um grupo de tarefas assíncronas e executar código após sua finalização.
\n\nlet group = DispatchGroup()\nlet queue = DispatchQueue.global(qos: .background)\n\nfor i in 1...5 {\n queue.async(group: group) {\n print("Tarefa \\(i) iniciada")\n Thread.sleep(forTimeInterval: Double.random(in: 0.5...2.0))\n print("Tarefa \\(i) concluída")\n }\n}\n\ngroup.notify(queue: DispatchQueue.main) {\n print("Todas as tarefas concluídas! Atualizando a UI.")\n}\n\nAsync/Await Moderno no Swift 5.5+
\n\nA partir do Swift 5.5, a Apple introduziu um novo modelo de concorrência baseado nas palavras-chave async e await. Isso torna o código assíncrono mais legível e compreensível.
Definição de Funções Assíncronas
\n\nFunções assíncronas são marcadas com a palavra-chave async, e sua chamada requer await:
import Foundation\n\n// Função assíncrona para carregar dados\nfunc fetchUserData() async throws -> String {\n let url = URL(string: "https://api.example.com/user")!\n let (data, _) = try await URLSession.shared.data(from: url)\n return String(data: data, encoding: .utf8) ?? "Sem dados"\n}\n\n// Uso de async/await\nfunc loadUserProfile() async {\n do {\n let userData = try await fetchUserData()\n await MainActor.run {\n print("Dados do usuário: \\(userData)")\n }\n } catch {\n print("Erro ao carregar: \\(error)")\n }\n}\n\n// Iniciando uma tarefa assíncrona\nTask {\n await loadUserProfile()\n}\n\nAsync let — Execução Paralela
\n\nA palavra-chave async let permite iniciar várias tarefas assíncronas em paralelo:
<