从进程ID /对象获取流程实例名称(更快的方式)

时间:2014-02-09 09:51:32

标签: c#

目前,从进程ID获取实例名称的解决方案来自以下代码。 问题是,这需要大量的时间和CPU资源!

也就是说,当您的系统运行至少100个进程时,需要花费大量时间循环遍历循环才能找到它。 (比如1到2秒)当我想要找到多达30个这样的过程时,最多需要30秒才能找到它们......

您不能简单地从流程对象中获取实例名称吗?

private static string GetProcessInstanceName(int pid)
{
  PerformanceCounterCategory cat = new PerformanceCounterCategory("Process");

  string[] instances = cat.GetInstanceNames();
  foreach (string instance in instances)
  {

     using (PerformanceCounter cnt = new PerformanceCounter("Process",  
          "ID Process", instance, true))
     {
        int val = (int) cnt.RawValue;
        if (val == pid)
        {
           return instance;
        }
     }
  }
  throw new Exception("Could not find performance counter " + 
      "instance name for current process. This is truly strange ...");
}

4 个答案:

答案 0 :(得分:1)

FranzHuber23 Solution仅通过查看以问题进程名称开头的进程来加快了原始速度。除此之外,还有一个改进使用PLINQ(并行LINQ)。可选地,Parallel.ForEach()或使用Task的构造可以提供类似的加速,但是这两个都将具有复杂的源,以仅返回第一个找到的内容并取消并发搜索(被ParallelEnumerable.FirstOrDefault()很好地隐藏了)

public static string PerformanceCounterInstanceName(this Process process)
{
    var matchesProcessId = new Func<string, bool>(instanceName =>
    {
        using (var pc = new PerformanceCounter("Process", "ID Process", instanceName, true))
        {
            if ((int)pc.RawValue == process.Id)
            {
                return true;
            }
        }

        return false;
    });

    string processName = Path.GetFileNameWithoutExtension(process.ProcessName);
    return new PerformanceCounterCategory("Process")
       .GetInstanceNames()
       .AsParallel()
       .FirstOrDefault(instanceName => instanceName.StartsWith(processName)
                                       && matchesProcessId(instanceName));
}

答案 1 :(得分:0)

这应该可以为您提供所有当前流程

var allProcesses = System.Diagnostics.Process.GetProcesses();

然后您可以遍历数组以查找您要查找的特定ID

答案 2 :(得分:0)

这是一个非常快速且运作良好的解决方案:

public static string GetInstanceNameForProcessId(int processId)
    {
        var process = Process.GetProcessById(processId);
        string processName = Path.GetFileNameWithoutExtension(process.ProcessName);

        PerformanceCounterCategory cat = new PerformanceCounterCategory("Process");
        string[] instances = cat.GetInstanceNames()
            .Where(inst => inst.StartsWith(processName))
            .ToArray();

        foreach (string instance in instances)
        {
            using (PerformanceCounter cnt = new PerformanceCounter("Process",
                "ID Process", instance, true))
            {
                int val = (int)cnt.RawValue;
                if (val == processId)
                {
                    return instance;
                }
            }
        }
        return null;
    }
来自Rick Strahl

。我唯一的问题与他博客评论中的问题相同:

  

有一点要提到与windows流程实例有关   名称是当其中一个进程退出时它们动态变化。

     

例如,如果镀铬#8退出,则镀铬#9将变为镀铬#8和   铬#10

     

将成为chrome#9。此时获取计数器的值   以前为chrome#10创建的将抛出异常。这是   如果你想监视多个实例,真的很烦人   多个流程,因为它涉及监控流程退出和   重新创建所有计数器(非常难看)。

     

一种方法是更改​​流程实例名称的方式   生成(见http://support.microsoft.com/kb/281884),但这有   使用perfmon api影响其他应用程序的可能性。

答案 3 :(得分:-1)

为什么不使用System.Diagnostics.Process.GetProcessById功能?

private static string GetProcessInstanceName(int pid)
{ 
    string name = String.Empty;
    Process proc = System.Diagnostics.Process.GetProcessById(pid);
    if(proc != null)
    {
        name = proc.ProcessName;
    }
    return name;
}