1

関数の実行にかかる時間を見つけようとしています。私はそれをこのようにやっています:

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に表示します。NDAに署名しているため、「入力の操作」でコードを共有することは許可されていません。しかし、私がそこで達成しようとしていることについてのあなたの質問に答えることはできます。助けてください。

編集2: 関数が最初に呼び出されたときに奇妙な値を取得しているようですが、@ Mike Banteguiが述べたように、JIT最適化が行われている必要があります。これは、現在考えられる唯一の解決策です(実行時間)は、時間をナノ秒単位で表示することです。C#で時間をナノ秒で表示するにはどうすればよいですか?

4

3 に答える 3

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 に答える
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 に答える
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);
}

これは、アイテムのリストが実際には非常に大きい場合に機能します。ただし、小さすぎる場合は、1 つのタイミングで複数回実行する必要があります。

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);
}

2 番目の例では、リストのサイズが小さすぎる場合、これを十分な大きさで実行するだけで、所要時間を正確に把握できます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 が彼の回答で行ったことを実行し、統計を行うための結果のリストを作成することです。最初のケースでは、個々の時間のリストを作成するだけです。2 番目のケースでは、複数の実行の平均タイミングのリストを作成します。これは、計算の時間がストップウォッチの最も細かい時間よりも短い可能性があるためです。

とはいえ、これらすべてには非常に大きな注意点が 1 つあります。何かを実行するのにかかる時間を正確に計算するのは非常に困難です。プロファイリングをしたいというのは素晴らしいことですが、SO について調査を行い、これを適切に行うために他の人が何をしたかを確認する必要があります。何かを悪いタイミングで実行するルーチンを作成するのは非常に簡単ですが、正しく実行するのは非常に困難です。

于 2011-07-19T01:12:51.100 に答える