有几个(吨)资源可用于从PID中查找父/子进程。太多甚至没有列出。我发现它们都非常慢。
让我们说我试图实现一个简单版本的Process Explorer。我可以使用Process.GetProcesses()轻松快速地枚举所有过程。但是,获取父/子关系需要永远。
我尝试过使用NtQueryInformationProcess方法,发现这需要~.1秒PER QUERY,即从一个进程获取一个父进程。为了让孩子们,你基本上必须构建整个树并在每个正在运行的进程中运行它。
然后我尝试使用ManagementObject查询进程的父进程,发现它在〜.12秒时更慢。
我尝试了另一种方式并使用ManagementObject直接查询子项,而不是查询父项和构建树。查询孩子的时间为.25到0.5秒PER QUERY。
使用这些方法中的任何一种,这意味着填充当前进程树的模型需要6-15整秒。这对我来说似乎很疯狂,比我估计的要高出一个数量级。我可以打开进程资源管理器,整个树中的父/子关系就在那里,即时。
我的电脑是否有问题导致它变慢?这只是因为某种原因需要花费更长时间来发现而不是你想的吗?过程资源管理器如何快速完成?
答案 0 :(得分:0)
所以,我想出了这个是一项重大改进。由于显然WMI是狗慢,我把它减少到所有进程及其父进程的单个查询,然后(用代码)填写子进程,以便它们易于检索。
关于这段代码的注释:它是一个静态类,起诉我。它被称为ProcessTree,但数据不是存储为树,它只是模拟树,再次起诉我。此外,可能存在错误,这是概念证明。
这将速度降低到三分之一秒,而不是5-15秒。由于这仍然很昂贵,因此它会在“超时”中指定间隔的数据。此缓存不适用于线程。
public static class ProcessTree
{
private static Dictionary<int, ProcessTreeNode> processes;
private static DateTime timeFilled = DateTime.MinValue;
private static TimeSpan timeout = TimeSpan.FromSeconds(3);
static ProcessTree()
{
processes = new Dictionary<int, ProcessTreeNode>();
}
public static List<int> GetChildPids(int pid)
{
if (DateTime.Now > timeFilled + timeout) FillTree();
return processes[pid].Children;
}
public static int GetParentPid(int pid)
{
if (DateTime.Now > timeFilled + timeout) FillTree();
return processes[pid].Parent;
}
private static void FillTree()
{
processes.Clear();
var results = new List<Process>();
string queryText = string.Format("select processid, parentprocessid from win32_process");
using (var searcher = new ManagementObjectSearcher(queryText))
{
foreach (var obj in searcher.Get())
{
object pidObj = obj.Properties["processid"].Value;
object parentPidObj = obj.Properties["parentprocessid"].Value;
if (pidObj != null)
{
int pid = Convert.ToInt32(pidObj);
if (!processes.ContainsKey(pid)) processes.Add(pid, new ProcessTreeNode(pid));
ProcessTreeNode currentNode = processes[pid];
if (parentPidObj != null)
{
currentNode.Parent = Convert.ToInt32(parentPidObj);
}
}
}
}
foreach (ProcessTreeNode node in processes.Values)
{
if (node.Parent != 0 && processes.ContainsKey(node.Parent)) processes[node.Parent].Children.Add(node.Pid);
}
timeFilled = DateTime.Now;
}
}
public class ProcessTreeNode
{
public List<int> Children { get; set; }
public int Pid { get; private set; }
public int Parent { get; set; }
public ProcessTreeNode(int pid)
{
Pid = pid;
Children = new List<int>();
}
}
如果有人有更好的解决方案,我会留下未回答的问题。
答案 1 :(得分:0)
您可以p / invoke SELECT ?name1 ?name2 WHERE {
{GRAPH ?graph { ?p1 foaf:name ?name1 }}
UNION {GRAPH ?graph { ?p1 foaf:knows ?p2 }}
UNION {GRAPH ?graph { ?p2 foaf:name ?name2 }}
{ select ?graph where { #here we get the list of graphs you created
?graph dc:creator ex:me ; dc:created ?date
FILTER( xsd:dateTime(?date) >= xsd:dateTime("2015-01-01") )
}
}
}
,Process32First
,Process32Next
。返回的CreateToolhelp32Snapshot
结构具有父进程ID,您可以使用它来建立父关系。这些API非常快。