Как да определите причината основната нишка да не отговаря с Omni Thread Library?

Платформа: Delphi с VirtualTreeView SVN 5.1.0 & OmniThreadLibrary 3 SVN & Delphi XE2

Първоначално мислех, че проблемът е VirtualTreeView. Трябва да добавя възел към VST на всеки 1s или по-малко. Но изглежда скоро или късно скоростта на процесора ще достигне 50% или повече, докато цялото приложение напълно не реагира.

  var FAbort:Boolean;
  .....

  procedure TrmMain.btnAddNodeClick(Sender: TObject);
    begin
      while not FAbort do
      begin
        VstMain.RootNodeCount:= VstMain.RootNodeCount + 1;
        Sleep(10);
        Application.ProcessMessages;
      end;
    end;

Някой може ли да помогне? TIA!

РЕДАКТИРАНЕ: Изглежда, че проблемът идва от OTL. Когато използвате кода по-горе, минимизирайте приложението, процесорът винаги е по-малко от 1%, дори променете 10ms заспиване на 1ms.

Но кодът по-долу ще възпроизведе проблема, който ме притеснява.

procedure TForm1.btn5Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to 1 do
    CreateTask(
      procedure(const Task: IOmniTask)
      begin
        while not FAbort do
        begin
          Task.Comm.Send(1, 0);
          Sleep(10);
        end;
      end).OnMessage(
      procedure(const Task: IOmniTaskControl; const Msg: TOmniMessage)
      begin
        vst1.AddChild(nil);
      end).Run;
end;

PS: За да избегна наводнението до OTL размера на опашката по подразбиране от 1000, АЗ имам заключване във всяка нишка, която изчаква завършването на възела за добавяне преди следващата операция Task.Comm.Send.

PPS: 10ms тук са само за бързо възпроизвеждане на проблема, а не в реална ситуация. Така че не си правете труда да питате защо?

Добре, заключението е: просто не добавяйте твърде много възли към един възел, ако трябва периодично да актуализирате този възел, колкото повече възли, толкова повече време на процесора за актуализирането им.


person XARA    schedule 10.01.2013    source източник
comment
Можете ли да добавите още лошотия? Безкраен цикъл, със Sleep плюс Application.ProcessMessages? Това е симфония на Bad. Какво ще кажете за добавяне на нарушения на достъпа и изтичане на памет? Сериозно. Какво си мислеше? Добавете TTimer и добавете възел от таймера, а не в цикъла. GUI приложенията не са ваши за управление с безкрайни цикли. Научете се да обичате управляваното от събития програмиране и да разберете, че Sleep(X) и Application.ProcessMessages не са начинът за решаване на вашите проблеми.   -  person Warren P    schedule 10.01.2013
comment
Спокойно, просто се опитвам да възпроизведа проблема, истинският код не е като този, който поставих по-горе. Събитието за добавяне на възел се случи само когато има нов журнал.   -  person XARA    schedule 10.01.2013
comment
Свържете профайлър и разберете къде прекарва времето си. Не забравяйте, че вътрешната структура на данните е двойно свързан списък, така че преминаването му отнема повече време, докато структурата расте.   -  person Rob Kennedy    schedule 10.01.2013
comment
Доста е трудно да разберете проблема, ако опишете поведение и след това публикувате фалшив код, а не истинския код.   -  person David Heffernan    schedule 10.01.2013
comment
защо трябва да добавяте възел на всеки 10ms? кой може да чете на всеки 10ms нов запис?   -  person Sir Rufo    schedule 10.01.2013
comment
Не можете да кажете, че сте изолирали проблема си, ако можете да го възпроизведете само с горния зъл код, но горният зъл код не е вашият истински проблем. Използвайте истински профайлър (AQTime) и ще знаете, вместо да играете игри.   -  person Warren P    schedule 10.01.2013
comment
Не разбирам връзката на минимизирането на приложението с нишката. Мислите, че нишката е проблемът, защото когато е минимизирано, приложението се държи по различен начин?   -  person Sertac Akyuz    schedule 10.01.2013
comment
Заглавието на въпроса ви е ужасно, тъй като сте открили, че това няма нищо общо с VirtualTreeView. Не виждам как вашият не-въпрос може да се превърне в истински въпрос. Какво ще кажете да го изтриете? Редактирах заглавието ви, за да премахна препратката към virtualtreeview, тъй като всъщност не е приложима, но въпросът ви все още ни моли да отстраним грешките във вашата гигантска купчина невидим код, така че гласувам да го затворя.   -  person Warren P    schedule 10.01.2013
comment
@Warren P: Благодаря за помощта. Кодирам приложение, което трябва да се изпълнява във фонов режим 24 часа, честотата на добавяне на възел не е толкова екстремна от демонстрацията, която качих в RapidShare. Но след часове и часове, в крайна сметка приложението ще бъде замразено.   -  person XARA    schedule 11.01.2013
comment
@Sertac Akyuz: ИМА разлика след минимизиране на приложението. За по-добро усещане изтеглете моя EVIL CODE, който качих в rapidshare. :Д   -  person XARA    schedule 11.01.2013
comment
@XARA - Не съм казал, че няма разлика. Попитах защо тази разлика трябва да е причинена от OTL.   -  person Sertac Akyuz    schedule 11.01.2013
comment
@Sertac Akyuz: Това е само за по-добър изглед на повишаването на честотата на процесора, като избягвате потребителския интерфейс да се актуализира.   -  person XARA    schedule 11.01.2013
comment
@XARA - Ах! Не съм разбрал тази част от въпроса. Благодаря за изчистването.   -  person Sertac Akyuz    schedule 11.01.2013


Отговори (2)


Според мен не трябва синхронно да актуализирате изглед, когато основният модел се промени, особено не Всеки път.

VirtualTreeView е визуален контрол. Човешките същества не трябва да виждат актуализацията на дървото в реално време, губят се повече от 3 пъти в секунда. Така че не го прави.

Вместо това актуализирайте своя модел (обекти, класове), задайте флаг за известяване и след това (от TTimer) направете асинхронно ЕДИНСТВЕНО актуализиране на VirtualStringTree.RootNodeCount, което се случва максимум 3 пъти в секунда. (Повече от една настройка на този флаг за актуализация на всеки 333 msec води до минимален период на изчакване от 333 msec, докато действително се актуализира.) Това е моят произволен потребителски интерфейс „по-бързо от това и е просто трептене и преливане и без никаква полза“ константа .

Собствените разработчици на Delphi се натъкнаха на това с VirtualTreeView, знам, защото регистрирах включената грешка в QC. Ако сте направили достатъчно съобщения „OutputDebugString“ в Delphi 2009, IDE няма да реагира. Защо? Защото те направиха това, което правиш ти. не го правете Не казвам, че щракването на потребителя трябва да причини 333 ms изчакване, преди екранът да се обнови. Казвам, че някакъв процес, който непрекъснато генерира съдържание на дърво, трябва да уведомява „контролера на изгледа“ на дървото за промени само 3 пъти в секунда, максимум.

person Warren P    schedule 11.01.2013
comment
П: Благодаря ви, разбрах мисълта ви. Лог изгледът на Delphi IDE наистина използва VST и НАИМАТЕ този проблем. Андреас Хаусладен, авторът на IDE Fix Pack, добави таймер, който е 70ms 0r 80ms интервал за актуализиране на VST и поправи този проблем. Ако дъщерните възли на един възел (в моя случай, RootNode) растат твърде бързо и твърде много, тогава режийните разходи за актуализиране на потребителския интерфейс всеки път са твърде скъпи. В моя код аз просто добавям лимит, който е 10 000, ако дъщерните възли са над него, запазете го, преди да ги изчистите всички, най-накрая това реши проблема ми. Както споменахте, периодичното добавяне на куп от тях е много по-ефективно . - person XARA; 12.01.2013
comment
Съжалявам, не накарах @ да работи. когато напиша името ти, то просто го изяжда. - person XARA; 12.01.2013
comment
Ако това реши проблема ви, трябва да редактирате заглавието и въпроса си, за да улесните намирането им за бъдещите хора. - person Warren P; 13.01.2013

Ако добавите възли с функцията AddChild(), нещата може да се представят по-добре от достъп до свойството RootNodeCount.

Например нещо като:

procedure TMyForm.OnTimer( Sender: TObject );
var
  Node: PVirtualNode;
begin
  Node := MyTree.AddChild( nil );
  // fill in details with GetNodeData( Node );

end;

Още по-добре: използвайте таймер и се опитайте да добавите няколко елемента на интервал от време:

procedure TMyForm.OnTimer( Sender: TObject );
begin
  AddToList( ... );
end;

procedure TMyForm.OnTimer( Sender: TObject );
var
  Node: PVirtualNode;
  Item: <Some iterator>;
begin
  MyTree.BeginUpdate();
  try
    for Item in <somelist> do begin
      Node := MyTree.AddChild( nil );
      // fill in details with GetNodeData( Node );
    end;
  finally
    MyTree.EndUpdate();
  end; 
end;
person Ritsaert Hornstra    schedule 10.01.2013
comment
Съгласен съм, че разширяването на RootNodeCount 100 пъти в секунда при стойности на RootNodeCount › 1000 може да стане все по-скъпо. Може да се случи някакво безумно възстановяване на цялото дърво. Но единственият начин да разберем е чрез нашата умна оригинална публикация, която моли човек да стартира в AQTime и да разбере сам. - person Warren P; 10.01.2013