2012-07-05 3 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 객체를 사용하여 시도 경과 시간이지만 그것은 나를 위해 작동하지 않습니다. for 루프 내에서 경과 시간을 비교

방법 1. : 여기에 2 개의 다른 내가 지금까지 시도한 방법은

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 밀리 초입니다.

for 루프를 200 밀리 초 이하로 엄격히 중단하라는 제안이 있으십니까? 감사합니다. .

+0

루프를 실행하는 스레드를 죽이는 것은 어떻습니까? 그래도 이상하지 않을 수도 있습니다. –

+0

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

+0

@Filip Ekberg, 좋은 지적! 그것을 고칠 필요가 있습니다. :) 그러나 그것은 내 문제를 해결하는 데 도움이되지 않을 수 있습니다. 그래도 좋은 연습입니다. 감사. – silverspoon

답변

5

는 빠른 비교를 위해, ("// 몇 가지 물건을 할"코드의 일부)이 있기 때문에 당신은 처리 중에 루프의 beggining에 체크인을하고도해야

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(); 
+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) {}'을 사용하고 두 번째 경우에는 주석문을 사용하여 루프를 테스트하십시오. ElapsedMilliseconds comparsion out this '//(sw.ElapsedMilliseconds + avg> 200) {}', 두 경우 사이의 시간차는 ElapsedMilliseconds comparsion에 의해 추가 된 시간 오버 헤드입니다. –

1

두 번째 것보다 간단하고 두 번째 것보다 정확할 가능성이 더 큽니다.

두 경우 모두 동일한 종류의 종료 조건을 가지므로 둘 다 동일해야합니다. 두 번째는 스레드와 수면의 사용으로 인해 훨씬 ​​더 복잡해 지므로 첫 번째 스레드를 사용합니다. 또한 두 번째 것은 수면으로 인해 덜 정확합니다.

TimeSpan.FromMilliseconds(200)에 상당한 시간이 걸릴 이유가 전혀 없습니다 (반복 할 때마다 호출하는 것은 물론).

+0

또한 두 번째 방법에서는'bDoExit'에 액세스 할 때 경합 조건이 생깁니다. 대신에 두 번째 방법을 리펙토링하고 어떤 종류의 취소 토큰을 사용할 수 있습니다 (http://msdn.microsoft.com/en-us/library/dd997364.aspx). 그것들은 멈추는 동작을 위해 설계되었습니다. –

+0

@ 재즈 (Jasd), 단 하나의 작가 만 있기 때문에 경쟁 조건이라고하지는 않습니다. 코드는 분명히'휘발성 '없이는 작동하지 않을 가능성이 있습니다 (루프 내에서 최적화 될 수 있기 때문에).하지만 결국 부울 변수의 변경을 가져옵니다 (단 하나의 전환 만 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 
} 
관련 문제