Lembra quantas vezes você precisou fazer um Loop em um Dataset para fazer uma soma, uma
contagem ou qualquer outra coisa…
Não gosto de fazer de novo algo que já fiz antes… Pensando nisto passei a usar “anonimous
method” do delphi para executar para mim os trechos repetitivos dos loops…
Veja como ficou.

[code lang=”pascal”]
type
TDatasetHelper = class helper for TDataset
public
procedure DoLoopEvent(AEvent: TProc<TDataset>); overload;
end;

procedure TForm34.execute;
var total:Double;
begin
// abere o Dataset com os dados.
alQuery1.sql.Text := ‘select codigo, total valor from sigcaut1 where data>=:data’;
alQuery1.ParamByName(‘data’).AsDateTime := strTodate(’01/01/2016′);
alQuery1.Open;
// fazer um loop para somar o total, usando metodos anonimos;
total := 0;
alQuery1.DoLoopEvent( procedure( ds:TDataset)
begin
total := total + ds.FieldByName(‘valor’).AsFloat; // executa o loop
end);
showMessage( FloatTOStr(total) ); // mostra o total da soma obtida no loop
end;

procedure TDatasetHelper.DoLoopEvent(AEvent: TProc;TDataset;);
var
book: TBookMark;
begin
book := GetBookmark;
try
DisableControls;
first;
while eof = false do
begin
AEvent(self);
next;
end;
finally
GotoBookmark(book);
FreeBookmark(book);
EnableControls;
end;
end;
[/code]

Código Original

Executar uma query em segundo plano (em paralelo) não …é difícil de fazer, o seu controle é que
pode ser mais complexo.
Para executar em segundo plano basta:

[code lang=”pascal”]
TThread.CreateAnonymousThread(procedure
begin
ALQuery1.sql.Text := ‘….’;
ALQuery1.Open;
end).Start;
[/code]

ou

[code lang=”pascal”]
TThread.CreateAnonymousThread(
procedure
var i:integer;
begin
for I := 0 to 10 do
begin
// faz alguma coisa…
AlQuery1.execSQL;
end;
end).Start;
[/code]

Um pensamento simplista é você criar uma conexão para cada QUERY em separado. Se você tem
um CONNECTION isolado para UMA QUERY, então é possível executá-la em paralelo dentro de
uma nova Thread;

Algumas idéias onde pode utilizar o processo em paralelo:
– quando precisa registrar um log em uma tabela;
– se for possível adiantar um SELECT que será utilizado mais a frente;
– se precisa rodar um loop que não tem dependência com os próximos passos da sequencia do
código;
– quando precisa fazer um somatório de dados na tabela para mostrar o seu valor na janela…. e
liberar o usuário para continuar fazendo outras coisas.
As vezes você pode por um SELECT em paralelo e disparar outra sequencia de código… e mais
adiante aguardar o primeiro SELECT concluir… para depois então continuar…. Este é assunto para
outro POST para tratar de TTASK.

Interfaces disponíveis através de TTASK que se encontra na unit System.Threading…
Enquanto ITask aguarda uma chamada x.start; para iniciar o processamento em uma thread
própria… o IFuture já inicia o processamento de imediato e aceita aguardar uma resposta após o
término de execução.

Exemplo ITask: (aguarda start para iniciar)
[code lang=”pascal”]
tsk := TTask.create( procedure begin
// código a ser executado
end);
tsk.start;
//pode ou não pedir para aguardar conclusão:
tsk.wait( 1000000);</pre>
[/code]

Exemplo IFuture: (inicia assim que for criado)
[code lang=”pascal”]
tsk = TTask.Future:boolean(
function:boolean
begin
// código…..
result := true; // resposta para o processamento
end);

resposta := tsk.value; // aguarda a thread terminal e pega o resultado
[/code]

Se precisar retornar mais de um valor, pode usar um RECORD:

[code lang=”pascal”]
TPessoa = record
nome:string;
idade:integer;
end;

tsk = TTask.Future:TPessoa(
function:TPessoa
begin
// código…..
result.nome := ‘Nome’; // resposta para o processamento
result.idade := 18;
end);

resposta := tsk.value; // aguarda a thread terminar e pega o resultado
if resposta.idade&gt;18 then
xxxxx
[/code]

Na versão XE7 foi incorporado ao Delphi o conceito de processamento paralelo. Antes já era
possível fazer algo parecido utilizando bibliotecas de terceiros
[http://www.omnithreadlibrary.com/index.htm http://andy.jgknet.de/blog/bugfix-units/asynccalls-
29-asynchronous-function-calls/].
Para tentar simplificar o conceito, diz paralelo quando consegue executar dois ou mais processos ao
mesmo tempo, daí o nome “paralelo”.

Exemplo utilizando TTask:

[code lang=”pascal”]
var
tsk: array [0 .. 2] of ITask;
i, n: integer;
begin
tsk[0] := TTask.create(
procedure
begin
TThread.Queue(nil, procedure
begin
caption := ‘xxx’; // sincronizar a atualização da janela.
end);
end);
tsk[0].Start; // inicia o processamento antes de criar as TTask seguintes
tsk[2] := TTask.create(
procedure
var
k: integer;
begin
i := 1;
sleep(1000);
for k := 0 to 10000 do
inc(i);
end);
tsk[1] := TTask.create(
procedure
var
k: integer;
begin
n := n;
for k := 0 to 1000 do
inc(n);
add( ‘N’);
end);
tsk[2].Start; // inicia o processamento
tsk[1].Start;
TTask.WaitforAll(tsk); // quando quer aguardar o termino de todas as TTasks
[/code]

Houve um tempo que executar tarefas em “background” era um tortura.
Com a evolução de hardware e software, fazer uso de computação paralela passou a ser tão
fácil quanto um desafio em resistir ao seu uso.

Introduzida na versão XE7, um “thread” passou a rodar considerando o balanceamento entre
os processadores presentes na unidade de processamento.

Associar o uso de métodos anônimos facilitou em muito todo o trabalho:
[code lang=”pascal”]
TThread.CreateAnonymousThread(
procedure begin
// execute aqui o seu código
….
// se precisar sincronizar atualização de
// controles da janela
TThread.Queue(nil,
procedure begin
// aqui deve incluir a atualização
// dos controles da janela;
// ex: label1.caption := ‘texto’;
end);
end).Start;
[/code]

A introdução de Class Helper no delphi ajudou o desenvolvedor a incluir novas
funcionalidades nas classes nativas do delphi – você tem uma idéia de um
recursos dos sonhos e gostaria de implementar lá na classe base, use Class
Helper.

Extendendo o TDataset:
[code lang=”pascal”]
TDatasetHelper = class helper for TDataset
public
procedure Run(AProc:TProc<TDataset>);
end;

procedure TDatasetHelper.Run(AProc: TProc<TDataset>);
begin // executa em um thread separada
TThread.CreateAnonymousThread(
procedure begin
if assigned(AProc) then
AProc(self);
end
).Start;
end;
[/code]
O exemplo implementa a capacidade de uso da “procedure” RUN(…) por
qualquer classe com herança de TDataset.

Trabalhando com o novo procedimento:

O procedimento RUN por finalidade executar em um processo paralelo (uma
nova TThread) a rotina que estiver implementando no TProc.
[code lang=”pascal”]
var total:double;
begin
query1.run(
procedure (ds:TDataset) // rotina a executar em paralelo.
begin
ds.first;
while ds.eof=false do
begin
total := total + xxxxx;
ds.next;
end;
end);
end;

[/code]

O Firebird aceita usar o Order By indicando o nome da coluna (o mais conhecido), o número da coluna ou pelo apelido da coluna.

Exemplo usando o nome da coluna:
[code lang=”SQL”]
select
codigo, nome, preco, (preco * 1.05) precoPrazo
from fb_prod
order by nome Rows 10
[/code]

Exemplo usando o número da coluna
[code lang=”SQL”]
select
codigo, nome, preco, (preco * 1.05) precoPrazo
from fb_prod
order by 4 Rows 10
[/code]

Exemplo usando o apelido da coluna:
[code lang=”SQL”]
select
codigo, nome, preco, (preco * 1.05) precoPrazo
from fb_prod
order by precoPrazo Rows 10
[/code]