Приложение Delphi замораживает всю систему win7 - PullRequest
1 голос
/ 16 июня 2010

У меня есть простая программа, которая сортирует текстовый файл по длине слов в строке эта программа работает без проблем на моей старой машине на базе XP теперь я запускаю эту программу на моей новой машине win7 / intel core i5, она замораживает всю систему и возвращается в нормальное состояние после завершения работы.

Я проверил код и обнаружил строку, вызывающую зависание

это была конкретная строка ...

caption := IntToStr(i) + '..' + IntTostr(ii);

я изменил его на

 caption :=   IntTostr(ii);  //slow rate change

и заморозки нет

и затем я изменил его на

caption :=   IntTostr(i);  //fast rate change

и снова зависает

мой код процедуры

 var tword : widestring;
      i,ii,li : integer;
 begin   
     tntlistbox1.items.LoadFromFile('d:\new folder\ch.txt');
     tntlistbox2.items.LoadFromFile('d:\new folder\uy.txt');
     For ii := 15 Downto 1 Do //slow change
      Begin
        For I := 0 To TntListBox1.items.Count - 1 Do //very fast change
        Begin     
          caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
          tword := TntListBox1.items[i];
          LI := Length(tword);
          If lI = ii Then
          Begin             
            tntlistbox3.items.Add(Trim(tntlistbox1.Items[i]));
            tntlistbox4.items.Add(Trim(tntlistbox2.Items[i]));
          End;
        End;
      End;
    end;

есть идеи почему? и как это исправить? я использую delphi 2007 / win32

Ответы [ 3 ]

10 голосов
/ 16 июня 2010

Это происходит внутри обработчика событий в форме?Я собираюсь догадаться, что это так.В этом случае «Заголовок» находится в области формы.Текст заголовка формы управляется не VCL, а Windows, и если вы отправляете новое сообщение WM_SETTEXT на каждой итерации цикла.

Подробное объяснение того, почему он делает то, что делаетпотребовалось бы знание внутренних компонентов Windows, которых у меня нет, но если бы я предположил, я бы сказал, что это примерно так:

Каждый раз, когда вы отправляете это сообщение WM_SETTEXT с новой подписью, Windowsпроверяет, чтобы убедиться, что он не идентичен существующему заголовку.Если это так, он может выйти немедленно.Вот почему редкое изменение (которое использует только ii) не замедляет работу вашей системы.Но если он меняется на каждой итерации, Windows должна выполнить какое-то переключение задач, чтобы изменить его.

Что касается того, почему это приведет к зависанию всей системы под ядром Vista (включая Win7), ноне XP, это совершенно за пределами моей области знаний.Но если вы пытаетесь сделать это как какой-то индикатор прогресса, есть лучшие способы, особенно если этот цикл настолько узок, насколько это выглядит.

Лучший способ обрабатывать обновления прогресса в узком цикле - этосчитать итерации и запускать только один раз каждые X раз.(100 или 1000 могут быть хорошими значениями для X, в зависимости от того, сколько раз он работает и как быстро все это занимает.) Это в основном то, что делает опция ii only.Вы также можете попытаться поместить индикатор прогресса в форму, чтобы измерить прогресс, вместо того, чтобы делать это с помощью заголовка формы.

2 голосов
/ 16 июня 2010

Первое: вы забыли вызовы tntlistbox3.items.BeginUpdate / tntlistbox3.items.EndUpdate (то же самое для tntlistbox4).

Второй: Почему моя программа работает быстрее, если я нажимаю и удерживаю строку заголовка?

Решение (пример):

const
  UpdateInterval = 500; // half a second
var 
  ...
  LastUpdate: Cardinal;
begin   
  ... 
  LastUpdate := GetTickCount + 100000; // forces first update
  For ii := 15 Downto 1 Do //slow change
  Begin
    For I := 0 To TntListBox1.items.Count - 1 Do //very fast change
    Begin     
      if (GetTickCount > (LastUpdate + UpdateInterval)) or
         (GetTickCount < LastUpdate) then
        caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
      ...
    end;
  end;
2 голосов
/ 16 июня 2010

Изменение заголовка формы освобождает целый ряд действий, особенно в Vista и Win7 с активным Aero.

Быстрая попытка будет использовать вместо этого TLabel для отображения прогресса. Что-то вроде

Label1.caption := IntToStr(i) + '..' + IntTostr(ii); //problemetic line               
Label1.Refresh; // or Repaint

должно сработать, если ваша этикетка не прозрачная или на стеклянной поверхности.

Вероятно, было бы лучше последовать совету Мэйсона Уилера и использовать индикатор прогресса. Поскольку общее число итераций равно 15*TntListBox1.items.Count, вы можете довольно легко рассчитать значение прогресса.

...