13

私のプロジェクト (C#、VS2010、.NET 4.0) では、特定のforループを 200 ミリ秒以内に終了する必要があります。そうでない場合は、残りの反復を実行せずに、この期間の後に終了する必要があります。ループは通常i = 0、約 500,000 から 700,000 になるため、合計ループ時間は異なります。

同様の次の質問を読みましたが、私の場合は役に立ちませんでした:

  1. C++ で 30 ミリ秒経過後にループを終了する最良の方法は何ですか?
  2. 特定の時間ループを実行する方法

これまでのところ、Stopwatchオブジェクトを使用して経過時間を追跡しようとしましたが、うまくいきません。これまでに試した2つの異なる方法を次に示します。

方法 1.forループ内の経過時間の比較:

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

for (i = 0; i < nEntries; i++) // nEntries is typically more than 500,000
{
      // Do some stuff
      ...
      ...
      ...

      if (sw.Elapsed > TimeSpan.FromMilliseconds(200))
          break;
}

sw.Stop();

if (sw.Elapsed > TimeSpan.FromMilliseconds(200))完了するまでに 200 ミリ秒以上かかるため、これは機能しません。したがって、私の場合は役に立たない。TimeSpan.FromMilliseconds()一般的にこれほど時間がかかるのか、それとも何らかの理由で私の場合だけなのかはわかりません 。

方法 2.時間を比較する別のスレッドを作成する:

Stopwatch sw = new Stopwatch();
sw.Start();                    
bool bDoExit = false;
int msLimit = 200;

System.Threading.ThreadPool.QueueUserWorkItem((x) =>
{
     while (bDoExit == false)
     {
        if (sw.Elapsed.Milliseconds > msLimit)
        {
            bDoExit = true;
            sw.Stop();
         }

         System.Threading.Thread.Sleep(10);
      }

});

for (i = 0; i < nEntries; i++) // nEntries is typically more than 500,000
{
      // Do some stuff
      ...
      ...
      ...

      if (bDoExit == true)
          break;
}

sw.Stop();

for ループには、いくつかの統計を出力する他のコードがあります。方法 2 の場合、forすべての反復が完了する前にループが確実に中断されますが、ループのタイミングは依然として 280 ~ 300 ミリ秒です。

厳密に 200 ミリ秒以内に for ループを中断するための提案はありますか? ありがとう。

4

5 に答える 5

9

より速く比較するには、比較してみてください

if(sw.ElapsedMilliseconds > 200)
   break;

たとえば、処理が 190 から開始される可能性があるため (ループの開始)、 20 まで続き、210 で終了します。

また、処理の平均実行時間を測定することもできます (平均時間に依存するため、これは概算です)。この方法では、ループは 200 ミリ秒以下で持続する必要があります。これは、コンソール アプリケーションの Main メソッドに簡単に配置できるデモです。アプリケーションに合わせて変更します。

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

        string a = String.Empty;
        int i;
        decimal sum = 0, avg = 0, beginning = 0, end = 0;
        for (i = 0; i < 700000; i++) // nEntries is typically more than 500,000
        {
            beginning = sw.ElapsedMilliseconds;
            if (sw.ElapsedMilliseconds + avg > 200)
                break;

            // Some processing
            a += "x";
            int s = a.Length * 100;
            Thread.Sleep(19);
            /////////////

            end = sw.ElapsedMilliseconds;
            sum += end - beginning;
            avg = sum / (i + 1);

        }
        sw.Stop();

        Console.WriteLine(
          "avg:{0}, count:{1}, milliseconds elapsed:{2}", avg, i + 1,
          sw.ElapsedMilliseconds);
        Console.ReadKey();
于 2012-07-05T07:11:46.523 に答える
2

別のオプションは、CancellationTokenSource を使用することです。

CancellationTokenSource source = new CancellationTokenSource(100);

while(!source.IsCancellationRequested)
{
    // Do stuff
}
于 2017-01-10T23:01:33.803 に答える
1

最初のものを使用してください - シンプルで、2 番目のものよりも正確である可能性が高くなります。

どちらの場合も同じ種類の終了条件があるため、どちらの動作も多かれ少なかれ同じになるはずです。2 番目は、スレッドとスリープを使用するためにはるかに複雑なので、最初のものを使用します。また、2番目のものは、睡眠のために精度がはるかに低くなります。

かなりの時間を費やす理由は絶対にありませんTimeSpan.FromMilliseconds(200)(すべての反復でそれを呼び出すだけでなく)。

于 2012-07-05T07:08:18.643 に答える
0

これが正確かどうかはわかりませんが、System.Timers.Timer:を使用して試してみる価値があると思います。

int msLimit = 200;
int nEntries = 500000;
bool cancel = false;

System.Timers.Timer t = new System.Timers.Timer();
t.Interval = msLimit;
t.Elapsed += (s, e) => cancel = true;
t.Start();

for (int i = 0; i < nEntries; i++)
{
    // do sth

    if (cancel) {
        break;
    }
}
于 2012-07-05T07:48:46.657 に答える