Pular para o conteúdo

Delphi Multithreading Moderno: Escreva Código Assíncrono Limpo e sem Complicação

Promessa Cumprida

Em 2025, durante minhas palestras na Embarcadero Conference, Luso Delphi e CodeRage, eu terminei minha apresentação com alguns slides “misteriosos” (Slides 17 e 18).

Eu falei sobre a jornada do desenvolvedor: saímos da complexidade manual da TThread, evoluímos para a eficiência da PPL (Parallel Programming Library), mas ainda faltava algo.

Quem usa PPL intensivamente conhece o problema. Para orquestrar pipelines complexos (baixar dados -> processar -> salvar -> atualizar UI), acabamos caindo na temida “Pyramid of Doom”: aninhamento excessivo de métodos anônimos, blocos try..except repetitivos e chamadas manuais de TThread.Queue para não congelar a tela.

Naquele slide, eu prometi uma visão de futuro: Uma interface fluente onde o código assíncrono pudesse ser lido como uma frase.

A espera acabou. A promessa foi cumprida.

Hoje, apresento oficialmente o Dext.Threading.Async — a implementação real daquele conceito, agora disponível no Dext Framework.

No meu livro, “Delphi Multithreading”, dedico capítulos inteiros ensinando como proteger suas threads, evitar Race Conditions e garantir que exceções não derrubem sua aplicação silenciosamente. Essa base teórica é inegociável.

Porém, no dia a dia, escrever toda essa infraestrutura “na unha” para cada botão do seu sistema é cansativo. Veja o padrão tradicional:

// O jeito padrão de usar a PPL
TTask.Run(procedure
begin
try
var Dados := DownloadBytes;
// Aninhamento...
TThread.Synchronize(nil, procedure
begin
AtualizaUI(Dados); // E se o Form já fechou? Access Violation.
end);
except
on E: Exception do HandleError(E); // Boilerplate repetitivo
end;
end);

Comparative Concept

Com o novo motor do Dext, abstraímos a complexidade da ITask, IFuture e o tratamento de exceções em uma sintaxe declarativa.

Vamos a um exemplo real? Imagine um Dashboard que precisa carregar 3 painéis pesados simultaneamente ao abrir a tela. Se fizéssemos sequencial, o usuário esperaria a soma dos tempos. Com o Dext, disparamos em paralelo e o código permanece limpo:

uses Dext.Threading.Async;
procedure TFormDashboard.LoadDashboard;
begin
// 1. Carrega o Perfil do Usuário (I/O Bound)
// Dispara e esquece a complexidade. O Dext gerencia a thread.
var Task1 := TAsyncTask.Run<TUserProfile>(
function: TUserProfile
begin
// Executa em Background Thread Pool
Result := UserService.GetProfile(Self.UserId);
end)
.ThenBy(procedure(User: TUserProfile)
begin
// Executa processamento adicional em background se necessário
LogAcesso(User);
end)
.OnComplete(procedure(User: TUserProfile)
begin
// Executa AUTOMATICAMENTE na Main Thread (seguro para VCL/FMX)
UserLabel.Caption := 'Bem vindo, ' + User.Name;
imgAvatar.Bitmap := User.Avatar;
end)
.OnException(procedure(E: Exception)
begin
// Tratamento centralizado de erro na Main Thread
ShowMessage('Erro ao carregar perfil: ' + E.Message);
end)
.Start; // Inicia a execução
// 2. Carrega Gráfico Financeiro (CPU Bound)
// Executa em PARALELO ao anterior
var Task2 := TAsyncTask.Run<TFinancialData>(
function: TFinancialData
begin
// Verifica cancelamento automaticamente antes de começar
Result := FinanceService.CalculateHeavyMetrics(CurrentYear);
end)
.OnComplete(procedure(Data: TFinancialData)
begin
ChartSales.Series[0].Add(Data.Values);
end)
.Start;
// 3. Atualiza Notificações
var Task3 := TAsyncTask.Run<Integer>(
function: Integer
begin
Result := NotificationService.CountUnread;
end)
.OnComplete(procedure(Count: Integer)
begin
Badge.Text := Count.ToString;
Badge.Visible := Count > 0;
end)
.Start;
// Aguarda todas as tarefas finalizarem
TAsyncTask.WaitForAll([Task1, Task2, Task3]);
end;

O que ganhamos aqui?

  1. Legibilidade: Lemos o código de cima para baixo, como uma história.
  2. Segurança de Thread: O OnComplete e OnException já garantem a sincronização com a Main Thread ou thread chamadora. Acabou o TThread.Queue espalhado pelo código.
  3. Propagação de Exceção: Se o GetProfile falhar, o fluxo pula o ThenBy e cai direto no OnException. Sem try..except poluindo a regra de negócio.

Mas e se o usuário fechar o formulário enquanto essas 3 tarefas estão rodando? Teremos um Access Violation ao tentar atualizar o UserLabel?

É aqui que entra a teoria que ensino no Capítulo 4 do livro: Cancelamento Cooperativo.

O Dext implementa o padrão ICancellationToken (inspirado no .NET) de forma transparente. Você pode passar um token para a tarefa, e a cadeia fluente verifica esse token antes de cada etapa.

// Vincula o Token ao ciclo de vida do Form
FTokenSource := TCancellationTokenSource.Create;
TAsyncTask.Run(...)
.WithCancellation(FTokenSource.Token) // A mágica acontece aqui
.OnComplete(...)
.Start;
procedure TFormDashboard.FormDestroy(Sender: TObject);
begin
// Ao destruir o form, cancela tudo que está pendente.
// O Dext impede que o OnComplete (que acessa componentes visuais) seja executado.
FTokenSource.Cancel;
end;

Isso resolve um dos bugs mais comuns e difíceis de rastrear em aplicações Delphi Multithread: o callback que tenta acessar um objeto destruído.

O Dext Framework entrega a ferramenta pronta para produção. Mas para usar multithreading com maestria, você precisa entender o que realmente está acontecendo. Por que o Pool de Threads é melhor que criar Threads manuais? O que é Context Switching? Como funcionam as Primitivas de Sincronização?

Delphi Multithreading Book

É por isso que digo que o Livro e o Framework formam um par perfeito:

Cumpri minha promessa feita no CodeRage. O Fluent Tasks não é mais apenas um slide de PowerPoint; é código real que você pode usar hoje para eliminar a complexidade do seu projeto.

Delphi Multithreading Book 3D

Convido você a baixar o Dext, testar o Dext.Threading.Async e, se quiser dominar a engenharia por trás disso, garantir sua cópia do livro no meu site.

Documentação Async API: https://github.com/cesarliws/dext/blob/main/Docs/async-api.md

Baixe o Dext: https://github.com/cesarliws/dext

Garanta o Livro: https://www.cesarromero.com.br/

Vamos codar (em paralelo)! 🚀

#Delphi #Multithreading #DelphiMultithreadingBook #DextFramework #AsyncProgramming #CodeRage #SoftwareArchitecture #OpenSource