Как определить причину, по которой основной поток не отвечает с Omni Thread Library?
Платформа: Delphi с VirtualTreeView SVN 5.1.0 и OmniThreadLibrary 3 SVN & Delphi XE2
Первоначально я думал, что проблема была VirtualTreeView. Мне нужно добавлять узел в VST каждые 1 с или менее. Но, похоже, рано или поздно частота процессора достигнет 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;
Кто-нибудь может помочь? ТИА!
РЕДАКТИРОВАТЬ: Кажется, проблема исходит от OTL. При использовании приведенного выше кода минимизируйте нагрузку на ЦП приложения менее чем на 1%, даже измените время ожидания 10 мс на 1 мс.
Но приведенный ниже код воспроизводит проблему, которая беспокоит меня.
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: 10 мс здесь просто для быстрого воспроизведения проблемы, а не в реальной ситуации. Так что не спрашивайте почему?
Итак, вывод таков: просто не добавляйте слишком много узлов на одном узле, если вам нужно периодически обновлять этот узел, чем больше узлов, тем больше процессорного времени для их обновления.
2 ответа
На мой взгляд, вы не должны синхронно обновлять представление при изменении базовой модели, особенно не каждый и каждый раз.
VirtualTreeView - это визуальный контроль. Людям не нужно видеть обновление дерева в реальном времени, тратится впустую больше, чем 3 раза в секунду. Так что не делай этого.
Вместо этого обновите модель (объекты, классы), установите флаг уведомления, а затем (из TTimer) выполните асинхронное одноразовое обновление VirtualStringTree.RootNodeCount, которое происходит максимум 3 раза в секунду. (Более чем одна установка этого флага обновления каждые 333 мсек приводит к минимальному периоду ожидания 333 мсек, пока он фактически не обновится.) Это мой произвольный пользовательский интерфейс "быстрее, чем этот, и это просто мерцание и отток, и никакой пользы" константа,
Разработчики Delphi столкнулись с этим с помощью VirtualTreeView, я знаю, потому что я зарегистрировал ошибку QC. Если вы сделали достаточно сообщений "OutputDebugString" в Delphi 2009, среда IDE перестает отвечать на запросы. Зачем? Потому что они сделали то, что ты делаешь. Не делай этого. Я не говорю, что пользовательский щелчок должен вызвать 333 мс ожидания, прежде чем экран обновится. Я говорю, что некоторый процесс, который генерирует древовидный контент непрерывно, должен только уведомлять "контроллер представления" дерева об изменениях максимум 3 раза в секунду.
Если вы добавите узлы с помощью функции 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;