计算执行一个函数所需时间的问题

本文关键字:时间 问题 函数 一个 执行 计算 | 更新日期: 2023-09-27 18:02:56

我试图找到运行函数所需的时间。我是这样做的:

SomeFunc(input) {
    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();
    //some operation on input          
    stopWatch.Stop();
    long timeTaken = stopWatch.ElapsedMilliseconds;
}

现在,根据SomeFunc的输入,注释中提到的"对输入进行某些操作"需要花费大量时间。

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

编辑:

有一个带有多个文本字段的UI,当按钮被单击时,它被委托给SomeFunc。SomeFunc根据输入(来自文本字段)进行一些计算,并在UI上显示结果。我不允许在"输入的一些操作"中共享代码,因为我已经签署了保密协议。然而,我可以回答你关于我在那里试图实现什么的问题。请帮助。

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

计算执行一个函数所需时间的问题

好吧,您没有在任何地方输出该数据。理想情况下你应该这样做。

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
}

事实上,您在第一次开始时得到的时间是错误的,其余时间是正确的。您不能只在第一次调用时中继来测量时间。然而,它似乎是操作太快,所以你得到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

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

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在他的回答中所做的事情,并建立一个结果列表来进行统计。在第一种情况下,您只需构建每个单独时间的列表。在第二种情况下,您将构建多次运行的平均计时列表,因为计算的时间可能小于Stopwatch中最细粒度的时间。

说了这么多,我想说的是,在所有这些中有一个非常大的警告:计算某些东西运行所需的时间是非常困难的。想要做分析是令人钦佩的,但你应该对SO做一些研究,看看其他人是如何正确地做这件事的。编写一个错误地计时的例程很容易,但很难正确地执行。