C# 为什么我在进程的运行持续时间内得到了不正确的值?

C# 为什么我在进程的运行持续时间内得到了不正确的值?,c#,validation,process,filtering,C#,Validation,Process,Filtering,基本上,我希望计时不是由代码触发的外部进程的运行持续时间。为了实现这一点,我使用以下代码(基于此)按流程名称订阅特定流程开始和结束的事件: addRuntimeData(双秒)方法定义为: public void addRuntimeData(double seconds) { this.runDurations.Add(seconds); if (this.runDurations.Count > Properties.Settings.Default.MaxRunDur

基本上,我希望计时不是由代码触发的外部进程的运行持续时间。为了实现这一点,我使用以下代码(基于此)按流程名称订阅特定流程开始和结束的事件:

addRuntimeData(双秒)
方法定义为:

public void addRuntimeData(double seconds)
{
    this.runDurations.Add(seconds);
    if (this.runDurations.Count > Properties.Settings.Default.MaxRunDurationData)
        this.runDurations.RemoveAt(0);
    this.updateLog();
}

public void updateLog()
{
    this.logfileDirectory = Properties.Settings.Default.LogfileDirectory;
    this.logfileFullPath = logfileDirectory + this.task.Name.toValidFilename() + this.logfileExtension;
    Directory.CreateDirectory(logfileDirectory); // create directory if it does not already exist
    this.toXElement().Save(this.logfileFullPath); // generate the XML and write it to the log file
}
现在,我正在尝试对我编写的测试进程计时,而测试进程所做的只是对
Console.WriteLine(“测试进程”)的一次调用,因此记录的持续时间的适当值应大致在0-2秒范围内

有时,我得到的值是适当的,有时我得到的值实际上不可能被记录下来,例如63619141321.2978秒。这大约相当于2017.3年,这让我认为这可能与记录为
01/01/0001 00:00:01
或类似内容的开始时间有关;这个问题可能与此有关吗


如果这是一个我无能为力的问题(例如,如果它与操作系统触发消息的方式/时间有关),有没有办法过滤掉这些明显无效的数据点?

关于
01/01/0001 00:00:01
,你基本上是对的

创建DateTime对象将在凌晨1/1/0001 12:00:00开始。您评论说,
processStart
声明时没有初始化,这意味着它的默认开始时间为1/1/0001 12:00:00 AM。我猜ProcessEnd是在ProcessStart被触发之前被触发的

下面的代码生成与您描述的类似的结果,并使用声明后未更改的DateTime

private static DateTime date;

public static void Main(string[] args) {
    const double largeVal = 63619141321;

    Console.WriteLine(date.ToString());

    double totalSeconds = (DateTime.Now - date).TotalSeconds;
    Console.WriteLine(totalSeconds - largeVal);

    Console.WriteLine("Press any key to continue . . . ");
    Console.ReadKey(true);
}

关于
01/01/0001 00:00:01
,您基本上是对的

创建DateTime对象将在凌晨1/1/0001 12:00:00开始。您评论说,
processStart
声明时没有初始化,这意味着它的默认开始时间为1/1/0001 12:00:00 AM。我猜ProcessEnd是在ProcessStart被触发之前被触发的

下面的代码生成与您描述的类似的结果,并使用声明后未更改的DateTime

private static DateTime date;

public static void Main(string[] args) {
    const double largeVal = 63619141321;

    Console.WriteLine(date.ToString());

    double totalSeconds = (DateTime.Now - date).TotalSeconds;
    Console.WriteLine(totalSeconds - largeVal);

    Console.WriteLine("Press any key to continue . . . ");
    Console.ReadKey(true);
}

根本问题是ManagementEventWatcher从根本上说是一种轮询机制,对于一个非常短的流程,结束事件可能在开始事件之前被拾取。如果启动时间从未初始化过(默认值为1/1/0001),那么您将看到您所描述的内容。实际上,这可能不是一个现实的用例,但正如您所观察到的,它是可能发生的。我认为解决这个问题的最好方法是不记录流程开始事件的开始时间

在计算总运行时间时,您实际上不需要查看process started事件。您可以从end事件中获取Win32_进程实例,并使用CreationDate计算进程的总运行时间。我注意到终止日期还没有确定。在这种情况下,我只使用触发结束事件的当前时间:

private static void ProcessEnded(object sender, EventArrivedEventArgs e)
{
    Console.WriteLine($"Process ended event at: {DateTime.Now}");
    var targetProcess = e.NewEvent.Properties["TargetInstance"].Value as ManagementBaseObject;
    if (targetProcess != null)
    {
        Console.WriteLine("Properties:");
        foreach (PropertyData data in targetProcess.Properties)
        {
            Console.WriteLine($"{data.Name} = {data.Value}");
        }

        DateTime creationDate = GetDateTimeOrDefault(targetProcess.Properties["CreationDate"], DateTime.Now);
        DateTime terminationDate = GetDateTimeOrDefault(targetProcess.Properties["TerminationDate"], DateTime.Now);

        var totalRunTime = (terminationDate - creationDate).TotalSeconds;
        Console.WriteLine($"Creation: {creationDate}, Termination: {terminationDate}, Elapsed: {totalRunTime}");
        // this.logger.addRuntimeData(totalRunTime);
    }
    else
    {
        Console.WriteLine("Could not get target process");
    }
}

private static DateTime GetDateTimeOrDefault(PropertyData managementDateProperty, DateTime defaultValue)
{
    string dateString = managementDateProperty.Value as string;
    if (!string.IsNullOrEmpty(dateString))
    {
        return ManagementDateTimeConverter.ToDateTime(dateString);
    }
    else
    {
        return defaultValue;
    }
}

根本问题是ManagementEventWatcher从根本上说是一种轮询机制,对于一个非常短的流程,结束事件可能在开始事件之前被拾取。如果启动时间从未初始化过(默认值为1/1/0001),那么您将看到您所描述的内容。实际上,这可能不是一个现实的用例,但正如您所观察到的,它是可能发生的。我认为解决这个问题的最好方法是不记录流程开始事件的开始时间

在计算总运行时间时,您实际上不需要查看process started事件。您可以从end事件中获取Win32_进程实例,并使用CreationDate计算进程的总运行时间。我注意到终止日期还没有确定。在这种情况下,我只使用触发结束事件的当前时间:

private static void ProcessEnded(object sender, EventArrivedEventArgs e)
{
    Console.WriteLine($"Process ended event at: {DateTime.Now}");
    var targetProcess = e.NewEvent.Properties["TargetInstance"].Value as ManagementBaseObject;
    if (targetProcess != null)
    {
        Console.WriteLine("Properties:");
        foreach (PropertyData data in targetProcess.Properties)
        {
            Console.WriteLine($"{data.Name} = {data.Value}");
        }

        DateTime creationDate = GetDateTimeOrDefault(targetProcess.Properties["CreationDate"], DateTime.Now);
        DateTime terminationDate = GetDateTimeOrDefault(targetProcess.Properties["TerminationDate"], DateTime.Now);

        var totalRunTime = (terminationDate - creationDate).TotalSeconds;
        Console.WriteLine($"Creation: {creationDate}, Termination: {terminationDate}, Elapsed: {totalRunTime}");
        // this.logger.addRuntimeData(totalRunTime);
    }
    else
    {
        Console.WriteLine("Could not get target process");
    }
}

private static DateTime GetDateTimeOrDefault(PropertyData managementDateProperty, DateTime defaultValue)
{
    string dateString = managementDateProperty.Value as string;
    if (!string.IsNullOrEmpty(dateString))
    {
        return ManagementDateTimeConverter.ToDateTime(dateString);
    }
    else
    {
        return defaultValue;
    }
}

可能会告诉您。@MattRowland lol rekt可能是因为在启动
processStart
并初始化
processStart
之前记录了一个持续时间。在这里,结束事件很可能在开始事件之前发生。观察者只是在投票。“WITHIN 1”子句的目的是设置轮询间隔。有时,最终进程观察者设法首先捕获其事件。如果开始时间没有初始化,那么它会给你你看到的。@mikez因此会在
ProcessEndWatcher
中将
内1
更改为
内2
,解决这个问题,因为
ProcessStartWatcher
被设置为
内1
,这将确保结束事件不会在开始事件之前触发?可能会告诉您。@MattRowland lol rekt可能是因为在启动
processStart
并初始化
processStart
之前记录了一个持续时间。在这里,结束事件很可能在开始事件之前发生。观察者只是在投票。“WITHIN 1”子句的目的是设置轮询间隔。有时,最终进程观察者设法首先捕获其事件。如果开始时间没有初始化,那么它会给你你看到的。@mikez因此会在
ProcessEndWatcher
中将
内1
更改为
内2
,解决这个问题,因为
ProcessStartWatcher
被设置为
内1
,这将确保结束事件不会在开始事件之前触发?但我将
processStart
初始化为
DateTime。现在
,而不是
new DateTime()
?@mjones.udri您能对定义processStart的行进行注释吗?它是一个类级变量<代码>私有日期时间进程开始,然后直到
进程启动
事件处理程序触发才初始化
this.processStart=DateTime.Now@mjones.udri,当您声明