如何以可用的速度在c#中获得PID的孩子

时间:2015-08-20 22:35:29

标签: c# process children

有几个(吨)资源可用于从PID中查找父/子进程。太多甚至没有列出。我发现它们都非常慢。

让我们说我试图实现一个简单版本的Process Explorer。我可以使用Process.GetProcesses()轻松快速地枚举所有过程。但是,获取父/子关系需要永远

我尝试过使用NtQueryInformationProcess方法,发现这需要~.1秒PER QUERY,即从一个进程获取一个父进程。为了让孩子们,你基本上必须构建整个树并在每个正在运行的进程中运行它。

然后我尝试使用ManagementObject查询进程的父进程,发现它在〜.12秒时更慢。

我尝试了另一种方式并使用ManagementObject直接查询子项,而不是查询父项和构建树。查询孩子的时间为.25到0.5秒PER QUERY。

使用这些方法中的任何一种,这意味着填充当前进程树的模型需要6-15整秒。这对我来说似乎很疯狂,比我估计的要高出一个数量级。我可以打开进程资源管理器,整个树中的父/子关系就在那里,即时。

我的电脑是否有问题导致它变慢?这只是因为某种原因需要花费更长时间来发现而不是你想的吗?过程资源管理器如何快速完成?

2 个答案:

答案 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") ) } } } Process32FirstProcess32Next。返回的CreateToolhelp32Snapshot结构具有父进程ID,您可以使用它来建立父关系。这些API非常快。