Как я могу минимизировать накладные расходы при обработке сообщений в длинном петле

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

  •  25-09-2019
  •  | 
  •  

Вопрос

У меня есть несколько длинных, но простых петлей в моей программе Delphi, которая может закрутить миллионы раз и занимать несколько секунд для выполнения. Код внутри цикла очень быстрый и был оптимизирован. Это просто занимает много времени, потому что это делается так много раз.

например:

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

Теперь я не хочу, чтобы моя программа не отзывчивала, поэтому я хочу добавить приложение. Процессаги внутри цикла. Но я также хочу добавленные заявления замедлить мою петлю как можно меньше.

Я следую за подключенным списком, поэтому у меня даже нет доступной доступной переменной и придется добавить один, если я хочу промежутки времени. Или мне придется добавить таймер, но нужно минимизировать проверку времени.

Как я должен реализовать это, чтобы минимизировать накладные расходы, которые добавлены?


Заключение:

На данный момент я делаю что-то вроде ответа APZ28.

Но это похоже на длительный срок, я должен реализовать какую-то резьбу для обработки этого. Спасибо за то, что указывали на это, потому что я думал, что Application.Processmessages был единственным способом сделать это.

Это было полезно?

Решение

Можете ли вы поместить рабочий контур в нить, освобождая основную нить для обработки петли GUI.

Другие советы

Положите его под нить не на третьем, так как он требует блокировки ресурса, если есть. Хорошая хитрость имеет счетчик, после обработки # цикла, вызовите процедуры

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;

Я бы также проголосовал за нить или что-то вроде Anreas ' Asycccalls.. Отказ Чтобы запретить пользователю выполнять любые недопустимые действия в течение необходимого времени, вы можете установить флаг, когда рутина запускается и сбросит его, когда она заканчивается (вам нужно обновить экран. Основной нить может проверить этот флаг и отключить все пораженные действия в их событии OnUpdate.

Лучший вариант состоит в том, чтобы переместить петлю в собственную рабочую нить, чтобы основной нить не заблокирован, то вам не нужно вызывать процедуры () вообще.

Однако, если вы должны сделать петлю в главной ните, вы можете использовать msgwaitformultiPleObject (), чтобы определить, когда вызовов ProcessMessages (), то есть:

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; 

В качестве альтернативы с 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; 

В качестве альтернативы с 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; 

Один из вопросов, который нужно решить, является ли ваша заявка продолжится до того, как вы получите ответ на то, что цикл рассчитывается. Если это не может, то не так много смысла в приложении «отзывчиво». Если вы пытаетесь обновить панель прогресса или что-то, вы можете позвонить .Repaint на управлении, содержащем панель прогресса каждое определенное количество итераций, чтобы вызвать перекраску прогресса.

Если приложение может продолжаться, по крайней мере, на некоторое время, затем вкладывая код в потоке - хорошая идея.

Помещение циклов в потоке, вероятно, в любом случае, особенно если вы хотите делать такие вещи, как, возможно, прервать обработку. Если вы никогда раньше не использовали темы, есть немного кривой обучения, но для простой петли, как вы описываете, есть много примеров в Интернете.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top