Pergunta

Eu tenho alguns loops longos, mas simples no meu programa Delphi, que podem fazer milhões de vezes e levar alguns segundos para executar. O código dentro do loop é muito rápido e foi otimizado. Demora muito porque é feito tantas vezes.

por exemplo:

Screen.Cursor = crHourGlass;
R := FirstRecord;
while R <> nil do begin
  { do something simple with R.Value }
  R := R.NextRecord;
end;
Screen.Cursor := crDefault;

Agora, não quero que meu programa não seja responsivo, então quero adicionar um aplicativo.processmessages dentro do loop. Mas também quero as declarações adicionais para desacelerar meu loop o mínimo possível.

Estou seguindo uma lista vinculada, por isso nem tenho uma variável de contagem disponível e teria que adicionar uma se quisesse intervalos. Ou eu teria que adicionar um cronômetro, mas precisava minimizar a verificação do tempo.

Como devo implementar isso para minimizar a sobrecarga que é adicionada?


Conclusão:

Por enquanto, estou fazendo algo como a resposta da APZ28.

Mas parece que devo implementar algum tipo de rosqueamento para lidar com isso. Obrigado por apontar isso, porque eu pensei que o aplicativo.processmessages era a única maneira de fazê -lo.

Foi útil?

Solução

Você pode colocar o loop de trabalho em um thread, liberando o thread principal para o processamento da GUI Loop.

Outras dicas

Coloque -o em Thread não é trival, pois requer recurso de compartilhamento de bloqueio, se houver. Um bom truque é ter um balcão, depois de processar o número de loop, Chamada Processmessages

var
  LoopCounter: Integer;

LoopCounter := 0;
R := FirstRecord;
while R <> nil do begin
  Inc(LoopCounter);
  if (LoopCounter >= ???) then
  begin
    LoopCounter := 0;
    Application.ProcessMessages;
  end;

  { do something simple with R.Value }
  R := R.NextRecord;
end;

Eu também votaria em um tópico ou algo como Anreas ' Assíncrono. Para proibir o usuário que executa quaisquer ações não permitidas durante o tempo necessário, você pode definir um sinalizador quando a rotina iniciar e redefini-la quando terminar (você deve atualizar o Screen.cursor de qualquer maneira). O encadeamento principal pode verificar esse sinalizador e desativar todas as ações afetadas em seu evento OnUpdate.

A melhor opção é mover o loop para seu próprio thread de trabalhadores para que o thread principal não esteja bloqueado, então você não precisa chamar processMessages ().

No entanto, se você precisar fazer o loop no encadeamento principal, poderá usar o msgwaitFormultiPleObject () para detectar quando chamar processMessages (), ou seja::

Screen.Cursor = crHourGlass; 
R := FirstRecord; 
while R <> nil do begin 
  { do something simple with R.Value } 
  if MsgWaitForMultipleObjects(0, nil, False, 0, QS_ALLINPUT) = WAIT_OBJECT_0 then
    Application.ProcessMessages;
  R := R.NextRecord; 
end; 
Screen.Cursor := crDefault; 

Alternativamente com PeekMessage ():

var Msg: TMsg;

Screen.Cursor = crHourGlass; 
R := FirstRecord; 
while R <> nil do begin 
  { do something simple with R.Value } 
  if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
    Application.ProcessMessages;
  R := R.NextRecord; 
end; 
Screen.Cursor := crDefault; 

Alternativamente com getQueuestatus ():

Screen.Cursor = crHourGlass; 
R := FirstRecord; 
while R <> nil do begin 
  { do something simple with R.Value } 
  if GetQueueStatus(QS_ALLINPUT) <> 0 then
    Application.ProcessMessages;
  R := R.NextRecord; 
end; 
Screen.Cursor := crDefault; 

Uma pergunta a decidir é se o seu aplicativo pode ou não continuar antes de ter a resposta para o que o loop está calculando. Se não puder, não há muito ponto no aplicativo "responsivo". Se você estiver tentando atualizar uma barra de progresso ou algo assim, poderá chamar. Reant no controle que contém a barra de progresso a cada certo número de iterações para fazer com que a barra de progresso repintar.

Se o aplicativo puder continuar, pelo menos por um tempo, colocar o código em um thread é uma boa ideia.

Colocar o código de loop em um encadeamento é provavelmente razoável de qualquer maneira, especialmente se você quiser fazer coisas como abortar o processamento. Se você nunca usou threads antes, há um pouco de curva de aprendizado, mas para um loop simples como você descreve, há muitos exemplos na web.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top