VirtualStringTree使用缓存系统更新数据



嗯,我使用VirtualStringTree来创建一种进程管理器…

我遇到了麻烦,因为更新树时将计时器设置为1000ms(对于检索大量数据(填充大约20列)的应用程序来说,cpu使用率太高)。

所以我想知道如何构建一种缓存系统,所以我可以更新树只有当发生变化时,我猜似乎是关键减少了我的应用程序的cpu使用率很多?

剪:

type
  TProcessNodeType = (ntParent, ntDummy);
  PProcessData = ^TProcessData;
  TProcessData = record
   pProcessName : String;
   pProcessID,
   pPrivMemory,
   pWorkingSet,
   pPeakWorkingSet,
   pVirtualSize,
   pPeakVirtualSize,
   pPageFileUsage,
   pPeakPageFileUsage,
   pPageFaults : Cardinal;
   pCpuUsageStr: string;
   pIOTotal: Cardinal;
...
  end;

如果我的应用程序启动,我用所有正在运行的进程填充树。请记住这只被调用一次,稍后当应用程序运行时,我得到了通过wmi终止的新进程或进程的通知,因此我不需要在稍后的计时器中调用以下过程来更新树…

procedure FillTree;
begin
var
  NodeData: PProcessData;
  Node: PVirtualNode;
  ParentNode: PVirtualNode;
  ChildNode: PVirtualNode;
  Process: TProcessItem;
  I : Integer;
begin
   ProcessTree.BeginUpdate;
   for I := 0 to FRunningProcesses.Count - 1 do
  begin
    Process := FRunningProcesses[i];
    NodeData^.pProcessID := ProcessItem.ProcessID;
    NodeData^.pProcessName := ProcessItem.ProcessName;
...

我有一个类,它将检索我想要的所有数据并将其存储到树中,如:

var
  FRunningProcesses: TProcessRunningProcesses;

所以如果我想枚举所有正在运行的进程,我只需给它一个调用:

  // clears all data inside the class and refills everything with the new data... 
  FRunningProcesses.UpdateProcesses;

问题从这里开始,当我枚举所有的东西,而不仅仅是已经改变的数据,这是相当cpu密集的:

procedure TMainForm.UpdateTimerTimer(Sender: TObject);
var
  NodeData: PProcessData;
  Node : PVirtualNode;
  Process: TProcessItem;
  I: Integer;
begin
   for I := 0 to FRunningProcesses.Count - 1 do
   begin
      Application.ProcessMessages;
      Process := FRunningProcesses[I];
      // returns PVirtualNode if the node is found inside the tree
      Node := FindNodeByPID(Process.ProcessID);
      if not(assigned(Node)) then
      exit;
      NodeData := ProcessVst.GetNodeData(Node);
      if not(assigned(NodeData)) then
       exit;
     // now starting updating the tree 
     // NodeData^.pWorkingsSet := Process.WorkingsSet; 
....

基本上,计时器只需要cpu使用情况和我可以从进程中检索的所有内存信息,如:

  • Priv。内存
  • 工作集
  • 峰值工作集
  • 虚拟大小
  • 页面文件使用
  • 页面文件使用峰值
  • 页面错误
  • Cpu使用
  • 线程数
  • 处理数
  • GDI句柄计数
  • 用户句柄数
  • Cpu总时间
  • 用户Cpu时间
  • 内核Cpu时间

所以我认为上面的数据必须缓存和比较,如果它改变或不只是想知道如何和什么将是最有效的?

您只需要更新当前可见的节点中的数据。您可以使用vst.getfirstvisible vst.getnextvisible来遍历这些节点。

第二种方法也很简单。使用对象而不是记录。对象使用示例代码

为不同的值使用getter。这些getter向进程查询值。也许这里需要一个极限。每秒钟刷新一次。

现在你只需要每秒钟将VST设置为无效状态。

vst.invalidate

这迫使VST重新绘制可见区域。

,但所有这些只在数据不按任何变化值排序时才有效。如果有必要,你需要更新所有的记录,我认为这是你的瓶颈。记住,COM和WMI比纯API慢得多。避免(慢)循环,并使用分析器来查找慢的部分。

我建议您将VT的节点数据直接指向TProcessItem。

职业:

  1. 去除FindNodeByPID。更新所有的项目FRunningProcesses,然后调用VT.Refresh。当过程是终止,从FRunningProcesses中删除相应项。目前你有相当昂贵的搜索在FindNodeByPID你遍历所有VT节点,检索它们的数据并检查PID。
  2. 去掉Process := FRunningProcesses[I]整个TProcessData记录的不必要的数据副本(顺便说一句,那应该这样做,使用指针代替)。
  3. 删除整个// now starting updating the tree
  4. 一般来说,通过这个改变,你减少了多余的实体,这对应用程序的更新和调试是非常好的。

反对:

    你必须保持VT和runningprocesses同步。但这是相当微不足道的。

相关内容

  • 没有找到相关文章

最新更新