在多线程环境中测量执行时间

10

我有一个应用程序,使用Task(TPL)对象进行异步执行。

主线程等待触发器(一些TCP数据包),然后执行多个任务。我想做的就是测量任务所花费的时间。

看一下代码。我有一些耗时操作(Generator),在Stopwatch的开始/停止中被封装。

Task.Factory.StartNew((t) => {

    Stopwatch sw = new Stopwatch();
    sw.Start();

    Generator g = new Generator();
    g.GenerateIntervals(); // lengthy operation

    sw.Stop();
    GlobalStopwatch.Add(sw.Elapsed);
});

这里有个问题。Stopwatch在Start()时使用DateTime.UtcNow.Ticks,然后在Stop()时再次使用。然后它将两者相减以获得经过的时间。
问题在于,在Generator.GenerateIntervals()执行耗时操作时,其他线程(在单线程系统中)可能会获取一些处理器时间。 这意味着秒表记录的经过时间不仅包含Generator.GenerateIntervals()时间,还包括其他线程在其中执行任务的时间。
是否有一种简单的方法可以精确地知道某个方法所需的处理器时间,而不包括由于时间共享机制而导致的其他线程执行时间?

2
注意:这不是重复的内容...它是一组不同的工具,需要专门针对 .Net TPL 实用程序进行回答。 - Timothy Khouri
为什么?你在比较线程机制吗?我从来没有理解想要在时序中消除环境变量,因为环境总是存在。 - Marc
@Marc,我觉得你没有理解这个问题...请看下面我的回复以获取更详细的信息。 - Timothy Khouri
4个回答

4
您的问题的答案是“不”... 不,您不能测量特定线程在CPU上累计的时间。
(副 rant:我真的希望人们在回答之前能阅读问题并理解它!!!)
好的,回到你的问题...最准确的做法是为每个任务启动单独的进程,然后测量进程的CPU时间(可在.Net中完成)...但这是过度的。
如果您需要如何做到这一点的帮助,您应该专门提出另一个问题。

啊...有点遗憾。这对项目来说并不是非常重要。我们只是想看看这个进程等待的时间相对于它执行操作的时间有多长。 - Kornelije Petak
我能理解...这真的很糟糕,不是吗 :P 我希望我也能获得每个线程的RAM和CPU使用情况。 - Timothy Khouri

1

这里有一篇不错的文章。你可以使用它,或者你可以在VS2010中使用内置的性能分析器来比较那些时间。


0
事实上,答案是肯定的(但需要使用interop)。
有一个名为QueryThreadCycleTime的WINAPI函数,可以正好做到这一点:
“检索指定线程的周期时间。”

有价值的发现——当您控制线程堆栈时。然而,这种方法可能无法与TPL一起使用,因为该库似乎使用线程池来执行其任务。 - Kallex

0
你可以使用Windows API的 QueryPerformanceCounter()QueryPerformanceFrequency() 方法来检索自计时器启动以来经过的毫秒数。
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Threading;

namespace Win32
{
    internal class WinTimer
    {
        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceCounter(
            out long lpPerformanceCount);

        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceFrequency(
            out long lpFrequency);

        private long startTime, stopTime;
        private long freq;

        // Constructor
        public HiPerfTimer()
        {
            startTime = 0;
            stopTime  = 0;

            if (QueryPerformanceFrequency(out freq) == false)
            {
                // high-performance counter not supported
                throw new Win32Exception();
            }
        }

        // Start the timer
        public void Start()
        {
            // lets do the waiting threads there work
            Thread.Sleep(0);

            QueryPerformanceCounter(out startTime);
        }

        // Stop the timer
        public void Stop()
        {
            QueryPerformanceCounter(out stopTime);
        }

        // Returns the duration of the timer (in seconds)
        public double Duration
        {
            get
            {
                return (double)(stopTime - startTime) / (double) freq;
            }
        }
    }
}

1
System.Diagnostics.Stopwatch 类可以为您完成所有这些操作。 - Brian Gideon
@BrianGideon:不知道呢!谢谢你的评论,Brian! - Steven Muhr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接