Fala ai Radizeiro e Radizeira, tudo bem com com vocês?

Durante essa nossa série sobre Paralelismo, temos conhecido mais sobre as Threads, e claro, aprendendo como trabalhar com Multi-Thread.

A cada post eu tenho curtido muito, e você que me segue sabe que sobre qualidade de código é algo que eu gosto e prego.

Você que tem o software e pensa na qualidade, e melhorar a entrega para os seus clientes, sabe o que é ter um código coeso e melhor estruturado.

Chega de ter que ficar horas tentando resolver problemas, e vamos melhorar a qualidade de nossos software.

Vamos acabar com travas constantes e filas enormes de chamados.

Vamos sem mais delongas, e vamos ao que interessa.

No post de hoje irei falar sobre o encadeamento das Tasks.

Vamos criar um novo projeto no Delphi, para construir esse encadeamento.

Já vimos sobre Task, ITask e IFuture, e já sabe como funciona, caso não tenha acompanhado a nossa série, acesse o primeiro post, para que possa estar bem situado.

Mas agora temos uma particularidade nas Tasks, são as tarefas.

Isso mesmo, podemos criar tarefas na utilização das Tasks.

Mas só para não confundir vocês, a Task não é uma Thread.

Ela é uma tarefa que roda em paralelo em uma Thread separada ou não.

Se você colocar para renderizar 100 Tasks, ela pode usar umas 2 a 3 Thread separadas para fazer essas tarefas.

Então não confunda uma coisa com a outra.

Mas vamos lá?

Lembra, como falei nos posts anteriores, que a Task implementa uma interface, a ITask.

Com isso você pode criar uma matriz com várias Tasks, ou seja, várias tarefas para serem executadas.

Quando você faz isso, você tem a possibilidades de administrar um array de tarefas, ou seja, múltiplas tarefas a serem executadas.

...
public
AllTasks : Array [0 .. 1] of ITask;
private
procedure RunTask(aLabel : TLabel; Timer : Integer; var aTask : ITask);
...
procedure TForm1.RunTask(aLabel : TLabel; Timer : Integer; var aTask : ITask);
begin
aLabel.Caption := '--';
aTask := TTask.Run(
procedure
begin
Sleep(Timer);
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
aLabel.Caption := Random(10).ToString;
end);
end);
end;

Observe que simplesmente declarei uma variável do tipo de uma array ITask, e no private criei um método para que execute uma tarefa em paralelo.

Esse método recebe um Label, por passagem de parâmetro, lembra que colocamos 3 labels na tela do nosso formulário, e um var do tipo ITask.

Quando clicarmos no botão iremos passar qual Label eu quero que esse botão mexa, e irei passar qual é a tarefa que será executada para esse label, que é executado dentro do RunTask.

Observe que o método simplesmente limpa o Label, e logo em seguida executa o processo.

Até então não tem nenhum mistério nisso que estamos fazendo.

Simplificando o que acabamos de implementar, vamos num botão e iremos executar essa tarefa.

procedure TForm1.Button1Click(Sender: TObject);
begin
RunTask(Label1, 3000, AllTasks[0]);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
RunTask(Label2, 7000, AllTasks[1]);
end;

Lembra que sentamos duas posições no nosso array?

Simplesmente eu chamei o método RunTask, passando o Label1 que quero alterar, e a tarefa que será executada.

A mesma coisa eu faço com o botão 2, onde eu seto o Label2 e qual tarefa será executada.

O que estamos fazendo aqui?

Tenho uma matriz de tarefas, com várias tarefas que precisam ser executadas.

Mas por que criamos essa matriz?

Porque com a matriz conseguimos gerenciar as tarefas da Task.

E agora que vem a parte do gerenciamento.

Como que gerenciamos essas tarefas?

Vamos no botão 3 criar esse gerenciamento.

procedure TForm1.Button3Click(Sender: TObject);
begin
Label3.Caption := '--';
TTask.Run(
procedure
begin
TTask.WaitForAll(AllTasks);
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
Label3.Caption := Label1.Caption + ' + ' + Label2.Caption;
end);
end);
end;

Observe que o Label3 recebe um valor fixo, só para não deixar vazio.

Logo em seguida executamos uma tarefa.

O que queremos é instanciar uma tarefa para o botão1 e para o botão2, e essas tarefas demoram uns 3 segundos.

Dentro da implementação do botão3, fiz com que ele aguarde até que as duas primeiras tarefas estejam concluídas, para aí sim ele ser executado.

Por este motivo chamei na TTask o WaitForAll, ou seja, espere por todas.

Onde ele aguarda a conclusão de todas as tarefas do array de ITask.

Vi o que aconteceu?

Ao clicar no botão 1 ele criou uma tarefa a ser executada em segundo plano que irá demorar 3 segundos, e ao clicar no botão 2, ele fez a mesma coisa sendo que aguarde 7 segundos.

Porém essas tarefas estão no mesmo array de tarefas.

E ao clicar no botão 3 ele ficou aguardando que todas as tarefas desse array fossem concluídas para só assim depois atualizar o label3 e concatenar os valores dos outros labels.

Muito legal não é?

Lógico que esse é um exemplo bem simples, mas com isso você pode fazer inúmeras coisas acontecerem.

E caso você tenha interesse de conhecer mais sobre PPL acessa o nosso portal do CLUBE DE PROGRAMADORES EM DELPHI, onde você não só terá conteúdos relacionados aos generics, mas uma quantidade enorme de conteúdos que poderá lhe ajudar muito no seu dia a dia, é uma verdadeira NETFLIX para os programadores Delphi.

CLIQUE AQUI E SAIBA MAIS SOBRE O CLUBE DOS PROGRAMADORES DELPHI