¿Cómo puedo minimizar la sobrecarga cuando el procesamiento de mensajes en un bucle largo

StackOverflow https://stackoverflow.com/questions/3402824

  •  25-09-2019
  •  | 
  •  

Pregunta

Tengo algunos bucles largos pero simples en mi programa de Delphi que millones de veces bucle puede tomar algunos segundos y de ejecutar. El interior de código del bucle es muy rápido y se ha optimizado. Solo se necesita mucho tiempo, ya que está hecho tantas veces.

por ejemplo:.

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

Ahora no quiero que mi programa sea no responde, por lo que desea agregar un Application.ProcessMessages dentro del bucle. Pero también quiero que las declaraciones añadido a frenar mi bucle lo menos posible.

Estoy siguiendo una lista enlazada, por lo que ni siquiera tienen una variable de conteo disponible y habría que añadir uno si quería intervalos. O tendría que añadir un temporizador, pero la necesidad de minimizar el tiempo de comprobación.

¿Cómo debo aplicar esto a minimizar la sobrecarga que se agrega?


Conclusión:

Por ahora, estoy haciendo algo así como la respuesta de APZ28.

Pero parece que a largo plazo debería aplicar algún tipo de roscar para manejar esto. Gracias por señalar esto, porque pensé que Application.ProcessMessages era la única manera de hacerlo.

¿Fue útil?

Solución

Se puede poner el lazo de trabajo en un hilo, liberando el hilo principal para el procesamiento de bucle de interfaz gráfica de usuario.

Otros consejos

se pone debajo de hilo no es trivial, ya que requiere de bloqueo de recurso compartido en su caso. Un buen truco está teniendo un mostrador, después de procesar # de bucle, ProcessMessages de llamada

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;

También me gustaría votar por un hilo o algo así Anreas' AsyncCalls . Prohibir al usuario hacer cualquier acción que no permitidos durante el tiempo necesario, se puede establecer un indicador cuando se inicia la rutina y restablecerla cuando se termina (lo que tiene que actualizar Screen.Cursor de todos modos). El hilo principal puede comprobar esta bandera y desactivar todas las acciones afectadas en su caso OnUpdate.

La mejor opción es mover el bucle en su propio subproceso de trabajo por lo que el hilo principal no está bloqueado, entonces no es necesario que ProcessMessages llamada () en absoluto.

Sin embargo, si debe hacer el bucle en el hilo principal, a continuación, puede utilizar MsgWaitForMultipleObject () para detectar cuándo llamar ProcessMessages (), es decir:

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 con 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 con 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; 

Una pregunta que decidir es si o no su aplicación puede continuar antes de que tenga la respuesta a la cualquiera que sea el bucle está calculando. Si no puede, entonces no tiene mucho sentido en la aplicación de ser "sensible". Si usted está tratando de actualizar una barra de progreso o algo, puede llamar .Repaint en el control que contiene la barra de progreso cada cierto número de iteraciones para hacer que la barra de progreso para volver a pintar.

Si la aplicación puede continuar, al menos por un tiempo, a continuación, poner el código en un hilo es una idea buena.

Poner el código de bucle en un hilo es probablemente razonable de todos modos, sobre todo si quieres hacer cosas como posiblemente abortar el proceso. Si usted nunca ha utilizado roscas antes, hay un poco de una curva de aprendizaje, pero para un bucle simple como se describe hay muchos ejemplos en la web.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top