Pergunta

Platform: Delphi with VirtualTreeView SVN 5.1.0 & OmniThreadLibrary 3 SVN & Delphi XE2

Originally I thought that the problem was VirtualTreeView. I need to add node to VST every 1s or less.But It seems soon or later the CPU rate will hit 50% or more ultil the whole application becomes completely non-responsive.

  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;

Anyone can help? TIA!

EDIT: It seems the problem comes from the OTL. When use the code above, minimize the application the CPU alway less than 1%, even change 10ms sleep to 1ms.

But, the code below will reproduces the problem which trouble me.

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: For avoid the flood to the OTL default 1000 queue size, I DO have a lock in each thread that wait for the add node completed before next Task.Comm.Send operation.

PPS: The 10ms here is just for quick reproduce the problem, not in real situation. So don't bother ask why?

OK,the conclusion is: simply not add too much nodes at single node if you need to update this node periodically, the more node the more cpu time to update them.

Foi útil?

Solução

In my view, you should not synchronously update a view when the underlying model changes, especially not Each and Every time.

The VirtualTreeView is a visual control. Human beings do not need to see the tree update in real time, any more than 3x per second is wasted. So don't do it.

Instead, update your model (objects, classes), set a notification flag, and then (from a TTimer), do an asynchronous SINGLE update of VirtualStringTree.RootNodeCount, that occurs 3x per second maximum. (More than one setting of this update flag each 333 msec leads to a minimum waiting period of 333 msec until it actually updates.) That's my arbitrary user-interface "faster than this and it's just flicker and churn, and no use whatsoever" constant.

Delphi's own developers ran into this with VirtualTreeView, I know because I logged the QC bug involved. If you did enough "OutputDebugString" messages in Delphi 2009, the IDE would become non-responsive. Why? Because they did what you're doing. Don't do it. I'm not saying that a user click should cause a 333 ms wait before the screen refreshes. I'm saying that some process that is generating tree content continuously should only notify the tree's "view controller" of changes 3 times per second, maximum.

Outras dicas

If you add nodes with the AddChild() function, things might peform better than accessing the RootNodeCount property.

Eg something like:

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

end;

Better yet: use a timer and try to add a few items per time interval:

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;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top