Delphi – Processamento paralelo para janela de progresso com LogEvents

Share Button

[usa LogEvents]
Tenho uma quantidade de produtos relativamente grande que requer processamento de custos de produção envolvendo custo de matérias primas, mão-de-obra e outros custos vinculado a célula de produção.

A modelagem prevê que uma ficha de produção pode conter outras fichas formando uma lista de dependências dos processos o que gera processamento recursivo de dependências.

Como se pode imaginar, não é um processamento sequenciado tão simples e pode ser demorado em face a profundidade da arvore de dependência que um produto pode exigir.

Então repensando os processos, o desafio passou exigir processamento em paralelo das fichas de tal forma que fosse possível processar uma quantidade de produtos ao mesmo tempo e aproveitando melhor os recursos da máquina;

Neste cenário, saber qual o estágio de processamento de cada ficha e o onde se encontra o cálculo passou a ser requisito de interação com usuário;

Para executar vamos utilizar da biblioteca de processamento em paralelo do Delphi (introduzido no XE7, no exemplo usamos Berlin).

Passos:

  • Isolar as conexões de banco de dados para trata-las individualmente por Task;
  • Criar infraestrutura de comunicação entre o processamento e feedback com usuário;
  • Tratar a sincronização de informações geradas pelas várias TTasks em andamento informando a janela de progresso do usuário;
imagem_janela
Tendo em mente que o controle possa ser utilizado em outras aplicações, o uso de um procedimento ANONIMOUS me parece bastante resistente a diversidade de códigos a que poderá vir a ser utilizado.
Veja como ficou o exemplo de execução:

procedure TForm8.Button1Click(Sender: TObject);
var
  LProgr: IProgressEvents;
  i: integer;
begin
  // inicializa a janela de progresso
  LProgr := TProgressEvents.new;
  LProgr.max := 100;  // opcional: marca o número máximo itens
  LProgr.MaxThreads := SpinEdit1.Value ;  // indica o número máximo de threads em paralelo
  LProgr.CanCancel := true;    :// marca se pode cancelar a operação

  for i := 1 to 100 do
  begin   // loop de demonstração - simulando uma lista de processos
    LProgr.Text := 'Produto: ' + intToStr(i);   // texto livre

    // onde as coisas acontecem.....
    // adiciona o processo a ser executado e aponta o método anonimous as ser executado pela TTask
    LProgr.add(i, 'Produto: ' + intToStr(i),    // processo a executar
      procedure(x: integer)
      var
        n: integer;
        msg: string;
      begin
        msg := 'Produto: ' + intToStr(x);    // processo em execução
        LogEvents.DoProgress(self, 0, etStarting, msg);  // notifica que o processo foi iniciado
        n := Random(10000);
        
        sleep(n);
        LogEvents.DoProgress(self, 0, etWorking, msg); // notifica que esta em execução
        // executa o código de calculo ... aqui...
        n := Random(10000);
        if LProgr.Terminated then exit;    // checa se o usuario cancelou a operação
        sleep(n);
      end);
    if LProgr.Terminated then
      break;
  end;
  LogEvents.DoProgress(self, 0, etAllFinished, '');  // sinaliza que todas os processo foram completados.
end;


Código fonte com o Exemplo e classes que implementam a janela de monitoramento do progresso de cada thread.