好吧,我正在使用VirtualStringTree创建一种流程管理器......
我遇到了麻烦,因为更新了树,定时器设置为1000毫秒(cpu使用率太高,我的应用程序检索了大量数据(填充了大约20列)。
所以我想知道如何构建一种缓存系统,这样我只有在发生变化时才能更新树,我猜这似乎是减少应用程序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;
...
我有一个Class,它将检索我想要的所有数据并将其存储到树中,如:
var
FRunningProcesses: TProcessRunningProcesses;
因此,如果我想枚举所有正在运行的进程,我只需要调用它:
// clears all data inside the class and refills everything with the new data...
FRunningProcesses.UpdateProcesses;
问题从这里开始,而我列举了所有内容,而不仅仅是那些已经发生变化且非常密集的数据:
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使用和我可以从以下过程检索的所有内存信息都需要定时器:
所以我认为上述数据必须以某种方式进行缓存和比较,如果它发生了变化,或者只是想知道如何以及最有效的方法?
答案 0 :(得分:0)
您只需更新当前可见的节点中的数据。
您可以使用vst.getfirstvisible
vst.getnextvisible
来迭代这些节点。
使用getter获取不同的值。 那些getter查询值的进程。 也许你需要一个限制。每秒刷新一次数据。
现在您只需要每秒将vst设置为无效状态。
vst.invalidate
这迫使vst重新绘制可见区域。
但只有当您的数据未按任何更改值排序时,所有这些都有效。 如果这需要你需要更新所有记录,这是你的瓶颈 - 我想。 记住COM和WMI比纯API慢得多。 避免(慢)循环并使用分析器找到慢速部件。
答案 1 :(得分:0)
我建议您将VT的节点数据直接指向TProcessItem。
Pro的:
FindNodeByPID
。只需更新所有项目
FRunningProcesses
,然后致电VT.Refresh
。当过程是
已终止,请从FRunningProcesses
删除相应的项目。
目前,您在FindNodeByPID
的搜索位置非常昂贵
循环遍历所有VT节点,检索其数据并检查
PID。Process := FRunningProcesses[I]
整个TProcessData记录的不必要的数据副本(顺便说一下,那个
无论如何应该使用指针)。// now starting updating the tree
区块。反对的: