2012-07-05 6 views
10

私のプロジェクト(C#、VS2010、.NET 4.0)には、特定のforループが200ミリ秒以内に終了する必要があります。そうでなければ、残りの反復を実行することなくこの期間の後に終了しなければならない。ループは一般にi = 0〜約500,000〜700,000になりますので、合計ループ時間は変化します。C#の特定の時間の後にループを終了

私は類似して、以下の質問を読みましたが、彼らは私の場合には助けにはならなかった。

  1. What is the best way to exit out of a loop after an elapsed time of 30ms in C++
  2. How to execute the loop for specific time

は、これまでのところ私は追跡するStopwatchオブジェクトを使用して試してみました経過時間がそれは私のために働いていない。

方法1.forループ内での経過時間を比較する:ここで私はこれまで試してみました2種類の方法ですif (sw.Elapsed > TimeSpan.FromMilliseconds(200))が完了するまでに200以上のミリ秒かかるので

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

は、これは動作しません。私の場合は役に立たない。私は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(); 

私はいくつかの統計情報を出力するループ内の他のコードを持っています。方法2の場合、forループがすべての反復を完了する前に確実に中断しますが、ループのタイミングはまだ280〜300ミリ秒です。

forループを200ミリ秒以下で厳密に破ることをお勧めしますか?おかげさまで

+0

ループを実行するスレッドを強制終了するのはどうですか?しかし、理想的ではないかもしれません。 –

+0

http://stackoverflow.com/questions/5945533/how-to-execute-the-loop-for-specific-time – akhil

+0

@Filip Ekberg、良い点!それを修正する必要があります。 :)しかし、それは私の問題を解決するのに役立つことはありません。しかし、それはよい練習です。ありがとう。 – silverspoon

答えて

5

if(sw.ElapsedMilliseconds > 200) 
    break; 

を比較してみてくださいそれがあるので、あなたは(コードの一部「//いくつかのものを実行してください」)、あなたのループのbegginingにしても、処理中にそのチェックを行う必要があります例えば、処理は190(ループの開始)から始まり、20は終了し、210は終了することが可能である。

処理の平均実行時間を測定することもできます(これは平均時間に依存するため近似しています)。この方法のループは200ミリ秒以下でなければなりません。ここでデモはメインメソッドに入れられますコンソールアプリケーションと簡単にアプリケーションのためにそれを変更します。

 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(); 
+0

複数の場所でタイミングを確認することをお勧めします。私のコードは "if(sw.ElapsedMilliseconds> 200)"の方がはるかに優れています。ありがとう。そして、はい、私はすでにループごとの平均時間を測定します。 – silverspoon

+0

「sw.ElapsedMilliseconds」ビットを追加した後、アプリケーションのテストが終了しました。指定された時間内にループを壊すことはできましたが、結果は以前の観測とよく似ています。つまり、sw.ElapsedMillisecondsは計算に時間がかかります。したがって、 'sw.ElapsedMilliseconds'を使用した後にループを中断することなくループを継続させると、ループ時間は約3秒(280〜300msではなく)です。非常に奇妙な。 – silverspoon

+0

'(sw.ElapsedMilliseconds + avg> 200)が破損するのではなく、最初のケースで' '' '(sw.ElapsedMilliseconds + avg> 200){}'を使用し、2番目のケースのコメントElapsedMilliseconds comparsionのように、この '/(sw.ElapsedMilliseconds + avg> 200){}'では、2つの場合の時間差は、ElapsedMillisecondsのコンパイルによって追加される時間オーバーヘッドです。 –

1

第1のものを使用してください。第2のものよりも正確である可能性があります。

どちらのケースも同じ種類の終了条件を持っているため、どちらも同じように動作するはずです。 2番目のスレッドは、スレッドとスリープの使用のためにはるかに複雑なので、私は最初のものを使用します。また、第2のものは、睡眠のせいでずっと正確ではない。

TimeSpan.FromMilliseconds(200)にはかなりの時間がかかります(また、すべての繰り返しで呼び出すだけでなく)。より高速な比較のために

+0

また、2番目の方法では、 'bDoExit'にアクセスする際に競合条件が発生します。 代わりに、2番目の方法をリファクタリングし、何らかの取り消しトークン(http://msdn.microsoft.com/en-us/library/dd997364.aspx)を使用することができます。これらは、停止する操作のために設計されています。 –

+0

@ジャスド、ただライターが1人しかいないので、競合状態とは言いません。コードは明らかに 'volatile'なしでは決してうまくいかない可能性があります(ループ内で最適化できるように...)。しかし、もしそれが最終的にブール変数の変化を拾うならば(単一の遷移だけがfalse->真実)。 –

+0

ブール値を読み書きするのはアトミックな操作なので、競合条件はありません。私の悪い。 –

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

別のオプションは次のようになりCancellationTokenSoを使用するurce:

CancellationTokenSource source = new CancellationTokenSource(100); 

while(!source.IsCancellationRequested) 
{ 
    // Do stuff 
}