1

我试图找出运行函数所花费的时间。我这样做是这样的:

SomeFunc(input) {
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();

    //some operation on input          

    stopWatch.Stop();

    long timeTaken = stopWatch.ElapsedMilliseconds;
}

现在,评论中提到的“对输入的某些操作”需要大量时间,具体取决于SomeFunc.

问题是当我SomeFunc从main调用多次时,我只在第一次正确地得到timeTaken,其余时间它被分配给0。上面的代码有问题吗?

编辑: 有一个带有多个文本字段的 UI,当单击一个按钮时,它被委托给 SomeFunc。SomeFunc 根据输入(来自文本字段)进行一些计算,并将结果显示在 UI 上。由于我签署了保密协议,因此我不允许在“输入某些操作”中共享代码。但是,我可以回答您关于我在那里努力实现的目标的问题。请帮忙。

编辑2: 似乎我在第一次调用函数时得到了奇怪的值,正如@Mike Bantegui提到的,​​必须进行JIT优化,这是我现在能想到的唯一解决方案(不为零执行时间)是以纳秒为单位显示时间的。如何在 C# 中以纳秒为单位显示时间?

4

3 回答 3

2

事实上,你在第一次开始时得到了错误的时间,而在剩下的时候得到了正确的时间。您不能仅在第一次通话时中继来测量时间。然而,这似乎是操作太快了,所以你得到了0结果。例如,要正确测量测试调用函数 1000 次以查看平均成本时间:

Stopwatch watch = StopWatch.StartNew();
for (int index = 0; index < 1000; index++)
{
    SomeFunc(input);
}
watch.Stop();
Console.WriteLine(watch.ElapsedMilliseconds);

编辑:

如何以纳秒为单位显示时间

您可以获取watch.ElapsedTicks然后将其转换为纳秒:(watch.ElapsedTicks / Stopwatch.Frequency) * 1000000000

于 2011-07-19T00:56:23.133 回答
2

好吧,您不会在任何地方输出该数据。理想情况下,您会做更多这样的事情。

void SomeFunc(input)
{
  Do sstuff
}

main()
{
  List<long> results = new List<long>();
  Stopwatch sw = new Stopwatch();
  for(int i = 0; i < MAX_TRIES; i++)
  {
     sw.Start();
     SomeFunc(arg);
     sw.Stop();
     results.Add(sw.ElapsedMilliseconds);
     sw.Reset();
  }

  //Perform analyses and results
}
于 2011-07-19T00:57:31.730 回答
1

作为一个简单的示例,请考虑以下(人为的)示例:

double Mean(List<double> items)
{
    double mu = 0;
    foreach (double val in items)
        mu += val;
    return mu / items.Length;
}

我们可以这样计时:

void DoTimings(int n)
{
    Stopwatch sw = new Stopwatch();
    int time = 0;
    double dummy = 0;

    for (int i = 0; i < n; i++)
    {
        List<double> items = new List<double>();
        // populate items with random numbers, excluded for brevity

        sw.Start();
        dummy += Mean(items);
        sw.Stop();
        time += sw.ElapsedMilliseconds;
    }

    Console.WriteLine(dummy);
    Console.WriteLine(time / n);
}

如果项目列表实际上非常大,则此方法有效。但如果它太小,我们将不得不在一个时间里进行多次运行:

void DoTimings(int n)
{
    Stopwatch sw = new Stopwatch();
    int time = 0;
    double dummy = 0;

    List<double> items = new List<double>(); // Reuse same list
    // populate items with random numbers, excluded for brevity

    sw.Start();
    for (int i = 0; i < n; i++)
    {
        dummy += Mean(items);
        time += sw.ElapsedMilliseconds;
    }
    sw.Stop();

    Console.WriteLine(dummy);
    Console.WriteLine(time / n);
}

在第二个例子中,如果列表的大小太小,那么我们可以通过简单地运行这个足够大的n. 虽然每个都有它的优点和缺点。

但是,在执行其中任何一项之前,我会事先进行“热身”计算:

// Or something smaller, just enough to let the compiler JIT
double dummy = 0;
for (int i = 0; i < 10000; i++) 
    dummy += Mean(data);
Console.WriteLine(dummy);

// Now do the actual timing

两者的另一种方法是按照@Rig 在他的回答中所做的,并建立一个结果列表来进行统计。在第一种情况下,您只需建立每个单独时间的列表。在第二种情况下,您将建立一个多次运行的平均时间列表,因为计算时间可能小于秒表中最细粒度的时间。

说了这么多,我想说所有这一切都有一个非常大的警告:计算某件事运行所需的时间很难正确完成。想要进行分析是令人钦佩的,但是你应该对 SO 做一些研究,看看其他人做了什么来正确地做到这一点。编写一个计时很糟糕的例程很容易,但很难做到正确。

于 2011-07-19T01:12:51.100 回答