性能计数器实例名称与进程名称



我正在连接Process类别中的各种性能计数器。我使用以下c#方法来确定获取计数器时要使用的实例名称

private const string _categoryName = "Process";
private const string _processIdCounter = "ID Process";
public static bool TryGetInstanceName(Process process, out string instanceName)
{
PerformanceCounterCategory processCategory = new PerformanceCounterCategory(_categoryName);
string[] instanceNames = processCategory.GetInstanceNames();
foreach (string name in instanceNames)
{
using (PerformanceCounter processIdCounter = new PerformanceCounter(_categoryName, _processIdCounter, name, true))
{
if (process.Id == (int)processIdCounter.RawValue)
{
instanceName = name;
return true;
}
}
}
instanceName = null;
return false;
}

现在,我注意到返回的实例名称通常与Process.ProcessName的值相匹配。

实例名称和进程名称是如何关联的

我之所以这么问,是因为我想简化例程中的foreach循环,这样我就不必为无法匹配当前进程的实例获取ID Process计数器。我设想的最后一种方法可能是这样的:

public static bool TryGetInstanceName(Process process, out string instanceName)
{
PerformanceCounterCategory processCategory = new PerformanceCounterCategory(_categoryName);
string[] instanceNames = processCategory.GetInstanceNames();
foreach (string name in instanceNames)
{
if (name /* more or less matches */ process.ProcessName)
{
using (PerformanceCounter processIdCounter = new PerformanceCounter(_categoryName, _processIdCounter, name, true))
{
// ...
}
}
}
instanceName = null;
return false;
}

看到没有答案,我进行了更多的试错测试,并观察到以下行为:

常规流程

对于具有给定名称的第一个常规进程,进程名称似乎与实例名称匹配。对于具有相同名称的后续进程,通过添加#1#2…来修改实例名称。。。

令人担忧的是,与进程关联的实例名似乎也可能发生更改。当数字序列中较早的进程结束时,似乎会发生这种情况。在确定实例名称和获取相关计数器之间存在竞争条件!

服务流程

在服务控制管理器下运行的Windows NT服务的行为方式与常规进程的行为方式相同。如果在数字序列中较早结束服务进程,则实例名称也会发生更改。

ASP.NET应用程序

除了进程名称为w3wp之外,在IIS下托管的应用程序也适用相同的假设。不同的应用程序。通过启动和停止应用程序,池肯定会得到不同的过程。pools,我确定在与上述相同的情况下,实例名称以相同的方式更改。

结论

我的结论是,实例名称总是以进程名称开头,方法可以修改如下:

public static bool TryGetInstanceName(Process process, out string instanceName)
{
PerformanceCounterCategory processCategory = new PerformanceCounterCategory(_categoryName);
string[] instanceNames = processCategory.GetInstanceNames();
foreach (string name in instanceNames)
{
if (name.StartsWith(process.ProcessName))
{
using (PerformanceCounter processIdCounter = new PerformanceCounter(_categoryName, _processIdCounter, name, true))
{
if (process.Id == (int)processIdCounter.RawValue)
{
instanceName = name;
return true;
}
}
}
}
instanceName = null;
return false;
}

此外,当使用返回的实例名时,确认上述竞赛条件的存在是至关重要的。

(如果没有进一步的输入,我会接受这个答案。请随时更正我。)

还要注意,如果您正在监视同一进程的多个实例,那么实例命名在不同类别之间是不一致的。因此,上面给出的解决方案只有在您从提取pid的同一类别中提取计数器时才有效。我确实发现pid在其他一些类别中,但不是全部,而且命名不一致。

这个解决方案不是更快一点吗:

public static bool TryGetInstanceName(Process process, out string instanceName)
{
PerformanceCounterCategory processCategory = new PerformanceCounterCategory(_categoryName);
string processName = Path.GetFileNameWithoutExtension(process.ProcessName);
string[] instanceNames = processCategory.GetInstanceNames()
.Where(inst => inst.StartsWith(processName))
.ToArray();
foreach (string name in instanceNames)
{
using (PerformanceCounter processIdCounter = new PerformanceCounter(_categoryName, _processIdCounter, name, true))
{
if (process.Id == (int)processIdCounter.RawValue)
{
instanceName = name;
return true;
}
}
}
instanceName = null;
return false;
}

(复制自Rick Strahl的博客,并进行了一些修改)。

然而,您需要注意:如果有多个进程具有相同的名称,并且其中一个进程退出,则所有进程的名称都会更改:

与windows进程实例名称相关的一件事是,当其中一个进程退出时,它们会动态更改。

例如,如果铬#8退出,铬#9将变为铬#8,铬#10>将变成铬#9。此时,获取之前为chrome#10创建的counter>的值将引发异常。这如果您想监视的多个实例多个进程,直到监控进程出口和重新创建所有计数器(真的很难看)。

一种方法是更改流程实例名称的生成方式>(请参阅http://support.microsoft.com/kb/281884)但是这个使用perfmonapi影响其他应用程序的可能性。

最新更新