Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > D2010: Регулярное обновление строки состояния


Автор: grh 29.2.2016, 15:04
Всем привет. Иногда при выполнении долговременных процедур Delphi-приложение "подвисает", и в том числе "подвисает" строка состояния. Что нужно сделать для того, чтобы строка состояния регулярно обновлялась?

Автор: Doga 29.2.2016, 15:39
Привет.

Application.ProcessMessages;

Хотя, если "подвисает" надолго, можно подумать об организации параллельного потока.  

Автор: dnek 1.3.2016, 15:00
Application.ProcessMessages не так хороша как Вам кажется и далеко не всегда подходит для прорисовки контролов, а в большинстве случаев её вообще не следует использовать.
Так что для выполнения "долгоиграющих" процедур наилучший (если не единственный) выход - отдельный поток.

Этот ответ добавлен с нового Винграда - http://ru.vingrad.com/D2010-Regulyarnoye-obnovleniye-stroki-sostoyaniya-id56d4342bae201554578b4567#findElement_E7045_56d58449ae2015570bdee1d6_0

Автор: Doga 1.3.2016, 20:44
2dnek:
Application.ProcessMessages не так плоха как Вам кажется  smile  

Иногда она хороша, иногда не очень...

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

Автор: dnek 2.3.2016, 08:22
Если использовать Application.ProcessMessages в теле цикла, то сильно грузится проц. Лучше уж тогда ввести какой-нибудь флаг и использовать связку Application.HandleMessage + обработчик Application.OnIdle. А вообще использование Application.ProcessMessages в долгоиграющих процедурах - плохой код (и уже давно). Это было допустимо в Delphi 7, а после (я имею года а не версию) уже считалось некорректным. Старайтесь писать чистый код!


Этот ответ добавлен с нового Винграда - http://ru.vingrad.com/D2010-Regulyarnoye-obnovleniye-stroki-sostoyaniya-id56d4342bae201554578b4567#findElement_E7045_56d678a2ae20155403deea8a_0

Автор: ZBugz 3.3.2016, 07:27
Цитата(dnek @ 2.3.2016,  08:22)
Если использовать Application.ProcessMessages в теле цикла, то сильно грузится проц. Лучше уж тогда ввести какой-нибудь флаг и использовать связку Application.HandleMessage + обработчик Application.OnIdle. А вообще использование Application.ProcessMessages в долгоиграющих процедурах - плохой код (и уже давно). Это было допустимо в Delphi 7, а после (я имею года а не версию) уже считалось некорректным. Старайтесь писать чистый код!


Этот ответ добавлен с нового Винграда - http://ru.vingrad.com/D2010-Regulyarnoye-obnovleniye-stroki-sostoyaniya-id56d4342bae201554578b4567#findElement_E7045_56d678a2ae20155403deea8a_0

Пусть таймер поставит и каждую секунду обновляет через Application.ProcessMessages и проц не грузится, делов то

Автор: Doga 4.3.2016, 00:09
2dnek:
Цитата

Если использовать Application.ProcessMessages в теле цикла, то сильно грузится проц.

Откуда Вы это взяли? С целью проверки этого утверждения был создан простенький тест.

В тесте реализовано 3 режима. В каждом из них производится получение системного времени, 
преобразование его в строку и её вывод на экран: 

Код

Panel1.Caption := DateTimeToStr(Now);


1.В первом режиме производится просто получение времени 10 000 000 раз в цикле без возможности 
обновить время на экране и с эфектом заморозки приложения до окончания работы цикла. 
Этот режим включён в тест для наглядности.

2.Во втором режиме  время опрашиватся в цикле пока не будет нажата кнопка "Стоп". 
Для обновления используется ProcessMessages. Время на экране обновляеттся своевременно,  
эфекта заморозки приложения нет.


2.В третем режиме  время опрашиватся в цикле параллельного потока пока не будет нажата кнопка "Стоп". 
Для обновления показаний времени используется Synchronize. Время на экране обновляеттся своевременно,  
эфекта заморозки нет.

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type

  TTimeThread =  class(TThread)
  protected
    procedure Execute; override;
    procedure UpdateTime;

  end;


  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    CanContinue : boolean;
    TimeThread : TTimeThread;
    
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//Заморозка
procedure TForm1.Button1Click(Sender: TObject);
var
  k : Integer;

begin
  Button1.Enabled := false;
  Button2.Enabled := false;
  Button3.Enabled := false;
  Button4.Enabled := false;

  TimeThread := nil;

  for k := 0 to 9999999 do
  begin
    //Конечно, Caption обновится только после выхода из цикла
    Panel1.Caption := DateTimeToStr(Now);
  end;

  Button1.Enabled := true;
  Button2.Enabled := true;
  Button3.Enabled := true;
  Button4.Enabled := true;
end;

//ProcessMessages
procedure TForm1.Button2Click(Sender: TObject);
begin
  Button1.Enabled := false;
  Button2.Enabled := false;
  Button3.Enabled := false;

  TimeThread := nil;

  CanContinue := true;

  while CanContinue do 
  begin
    Panel1.Caption := DateTimeToStr(Now);
    Application.ProcessMessages;
  end;

  Button1.Enabled := true;
  Button2.Enabled := true;
  Button3.Enabled := true;
end;

//Поток
procedure TForm1.Button3Click(Sender: TObject);
begin
  Button1.Enabled := false;
  Button2.Enabled := false;
  Button3.Enabled := false;

  TimeThread := TTimeThread.Create(true);
  TimeThread.FreeOnTerminate := true;
  TimeThread.Resume;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  CanContinue := false;

  if (TimeThread <> nil) then
  begin
    TimeThread.Terminate;
    TimeThread := nil;

    Button1.Enabled := true;
    Button2.Enabled := true;
    Button3.Enabled := true;
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  if (TimeThread <> nil) then
  begin
    TimeThread.Terminate;
  end;
end;

procedure TTimeThread.Execute;
begin
  while not Terminated do 
  begin
    Synchronize(UpdateTime);
  end;
end;

procedure TTimeThread.UpdateTime;
begin
  Form1.Panel1.Caption := DateTimeToStr(Now);
end;

end.



В итоге выяснилось следующее.

В первых двух режимах распределение нагрузки по ядрам процессора (у меня 8 виртуальных) 
выглядит не очень четким, как бы размазанным по всем ядрам, хотя из них можно выделить 
2 или 3 с большей нагрузкой и у одного из этих трёх больше чем у двух других. Графики 
нагрузки в большинстве случаев имеют резкую пилообразную форму, от мнмимума до максимума.
Интегральная нагрузка на процессор 13-14%.

В третем режиме явно видно, что нагружены только 2 ядра из 8ми. Одно ядро имеет 
нагрузку ~30% - очевидно главный поток приложения, втрое ядро нагружено на  ~ 80% - параллелный 
поток приложения, занимающийся опросом времени. Графики нагрузки имеют вид практически 
горизонтальных линий, с небольшим дребезгом.
Интегральная нагрузка на процессор 14-16%, т.е. немного больше чем в первых двух режимах. 

Т.о. отбросив эти 2% (т.е. мою гипотетическюю предвзятость в оценке результатов этого теста), 
можно сделать вывод, что независимо от способа обновления данных на экране, нагрузка 
на процессор не меняется. Более того. Одна и та же нагрузка, распределённая по большему 
количеству ядер, приводит к более равномерному нагреву, снижая локалные 
перегревы процессора, что положительно сказывается на его работе.


Да и вообще, зачем их (процессоры) жалеть? Пусть вкалывают! Они для того и созданы!
Будем сюсюкать с ними - так они нам на шею сядут, и пойдут потом всякие СкайНеты и Генезисы!
Надеюсь, все мы помним, чем это может закончится...

Или не помним  smile 








Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)