2010-11-18 6 views
15

C#을 사용하여 가능한 가장 높은 해상도 타이머를 사용하고 싶습니다. 예를 들어, 나는 11 tick마다 event를 발생시키고 싶다. (tick은 PC에서 가능한 가장 높은 counter라고 들었다.) 나는 타이머를 시험해 본 결과, 최소 경과 시간이 밀리 세컨드 (miliseconds)임을 알게되었다. 스톱워치를 보았지만 스톱워치는 이벤트를 제기하지 않습니다.고해상도 인터벌/타이머에서 이벤트 발생

감사합니다.

+2

왜 세계에서 11 틱마다 이벤트를 발생시키고 싶습니까? 코드 프로파일 링에 이것을 사용하고 있습니까? –

+5

질문에 답변하지 않았습니다. 11 틱은 단지 예일뿐입니다. 내가 원하는 건 고해상도 타이머 뿐이야. 가능한 한 최대 1 tick. 네, 일부 벤치마킹을위한 응용 프로그램을 개발 중입니다. –

+0

이것이 제가 downvoting 코멘트를 지원하는 이유입니다 –

답변

18

멀티미디어 타이머를 사용하면 초당 약 1000 회의 이벤트가 발생합니다. 이 코드는 도움이 될 것입니다.

 public delegate void TimerEventHandler(UInt32 id, UInt32 msg, ref UInt32 userCtx, UInt32 rsv1, UInt32 rsv2); 

    /// <summary> 
    /// A multi media timer with millisecond precision 
    /// </summary> 
    /// <param name="msDelay">One event every msDelay milliseconds</param> 
    /// <param name="msResolution">Timer precision indication (lower value is more precise but resource unfriendly)</param> 
    /// <param name="handler">delegate to start</param> 
    /// <param name="userCtx">callBack data </param> 
    /// <param name="eventType">one event or multiple events</param> 
    /// <remarks>Dont forget to call timeKillEvent!</remarks> 
    /// <returns>0 on failure or any other value as a timer id to use for timeKillEvent</returns> 
    [DllImport("winmm.dll", SetLastError = true,EntryPoint="timeSetEvent")] 
    static extern UInt32 timeSetEvent(UInt32 msDelay, UInt32 msResolution, TimerEventHandler handler, ref UInt32 userCtx, UInt32 eventType); 

    /// <summary> 
    /// The multi media timer stop function 
    /// </summary> 
    /// <param name="uTimerID">timer id from timeSetEvent</param> 
    /// <remarks>This function stops the timer</remarks> 
    [DllImport("winmm.dll", SetLastError = true)] 
    static extern void timeKillEvent( UInt32 uTimerID); 

타이머를 실행 한 후에 타이머를 중지하십시오. 그들은 당신의 시스템에 상당히 무겁습니다. 모든 예외를 catch하고 이벤트 처리기에서 벗어나지 않도록하십시오.

* 5 개 이상의 타이머를 시작하면 대부분의 시스템이 심각하게 느려집니다! 가능한 한 적은 코드를 이벤트 처리기에서 실행하고 실행 코드가 1 밀리 초보다 빠르거나 심각한 문제에 직면하는지 확인하십시오. 레이블 표시를 늘리기 위해 10-50 틱마다 대리인을 시작했습니다.

Thread.Sleep에서 발생하는 정상적인 스레드 전환은 코드에서 하나의 스레드 슬롯을 제거하고 약 40 밀리 초가 소요됩니다. 일부 NT 커널 호출로 스레드 전환 빈도를 늘릴 수도 있지만 그렇게하지 마십시오.

4

다양한 타이머 클래스는보다 큰 세분성을 사용합니다. Threading.Timer와 Timers.Timer는 1/64 초를 사용하는데 이는 15.625 밀리 초입니다.

당신이 말하는 'tick'이 DateTime 클래스, TimeSpan 클래스에서 사용되는 100 나노초 틱이고 스톱워치에 의한 출력 인 경우 요청한 11 tick 길이는 1,100 나노초입니다. 1.1 마이크로 초. 내가 아는 한, 당신에게 그 해결책을 줄 수있는 타이머가 내장되어 있지 않다. 1.1 마이크로 초마다 이벤트가 발생하기를 정말로 원한다면, '타이머'에 대한 아이디어를 제거하고 짧은 지연에 대해 생각해야합니다. 스레드의 우선 순위를 높이고 루프에서 이벤트를 실행하십시오. 1.1 마이크로 초가 시스템 스케줄러의 타임 슬라이스보다 작다고 생각하기 때문에 Thread.Sleep()을 호출하지 마십시오. 대신 지연 루프를 수행해야합니다.

또한 시간 간격은 매우 작습니다. 1.1 마이크로 초는 2GHz 프로세서에서 2,200 프로세서 사이클에 불과합니다. 사소한 금액은 아니지만 많은 작업을 완료하는 데는 많은 시간을 필요로하지 않습니다. 귀하가 귀하의 의견에 언급 한 1 tick을 말하면, 그것은 단지 200 프로세서 사이클입니다. 그것은 수십 번의 수학 연산을 수행 할 수있는 충분한 시간이며, 아마도 하나의 함수를 호출 할 수 있습니다.

+0

저에게 관심있는 틱은 초시계입니다. 주파수는 약간 틱입니다. 즉, 프로세서 사이클 틱입니다. –

+3

프로세서주기 틱 (예 : 2GHz)? 0.5 나노 초입니다. 가장 간단한 프로세서 명령어를 제외하고는 모두 여러 프로세서 사이클을 사용합니다. 예를 들어, 한주기에서 정수를 증가시킬 수 있지만 'if'문은? 그건 10 프로세서 사이클, 5 나노초 정도입니다. 그 빈도로 타이머를 검사 할 방법이 없으며, 모든 작업을 수행 할 필요가 없습니다. –

+4

잠깐, 나는 그것을 뒤로 가져 간다. 1 프로세서 사이클의 빈도를 가진 타이머가있는 방법이 있습니다 : 스레드를 높은 우선 순위로 설정하고 while (true) {...}' –

14

먼저 하드웨어와 소프트웨어에서 모두 노출되는 제한 때문에 컴퓨터에서 정확한 타이밍을 수행하는 것은 매우 어렵습니다. . 좋은 소식은 이런 종류의 정밀도는 거의 필요 없다는 것입니다. 10 진드기는 미미한 작은입니다. 이 간격에서 CPU에 의해 수행되는 작업은 거의 없으며 결코 통계적으로 중요하지 않습니다.

Windows 시계의 정확도는 약 10 밀리 초 (이전 버전에서는 적음)입니다. DateTime.UtcNow으로 전화를 걸어 코드를 작성하면 그보다 더 좋은 결과를 얻지 못할 것입니다.

질문에서 "이벤트 발생"에 대해 이야기합니다. 문제는 특정 간격으로 이벤트를 발생시키는 시간 유지 객체의 유일한 유형이 Timer 객체라는 것입니다. .NET Framework (System.Timers.Timer, System.Threading.TimerSystem.Windows.Forms.Timer)의 3 가지 다른 화신으로 사용할 수 있지만 모두 고유 한 사용 시나리오와 관련성이 있지만 은 어느 곳에서나 정확한 위치를 보장하지 않습니다. . 그들은 그렇게하도록 설계되지 않았으며, Windows API에 의해 노출 된 동등한 기능이 이러한 유형의 정밀도를 제공하지도 않습니다.

내가 왜 이렇게하고 싶은지 묻는 이유와 벤치마킹을 시도하는 이유는 전체 게임을 변경하기 때문입니다. .NET Framework (버전 2.0 현재)는 정확하게 벤치마킹 또는 성능 프로파일 링과 같은 상황에 대한 경과 시간을 정확하게 측정하도록 설계된 Stopwatch object을 제공합니다. Stopwatch은 Windows API 함수 QueryPerformanceFrequencyQueryPerformanceCounter을 단순히 래핑합니다 (의도 한 용도에 대한 제 제안을 확인해야 함). 우리는 이전 버전의 프레임 워크에서 이러한 유형의 기능에 액세스하기 위해 이러한 함수를 P/호출해야했지만 이전에는 편리하게 내장되었습니다. 벤치마킹을 위해 비교적 높은 해상도의 타이머가 필요한 경우 Stopwatch이 최선의 방법입니다 . 이론 상으로는 서브 마이크로 초 타이밍을 제공 할 수 있습니다.

하지만 문제가있는 것은 아닙니다. 이벤트를 발생시키지 않으므로 현재 디자인이 이벤트 핸들링에 의존하는 경우이를 다시 고려해야합니다. 그리고 도 완벽하게 정확하다는 보장은 없습니다. 물론, 주어진 하드웨어 제한 인이 가능한 최대 해상도 인 이있을 수 있지만 이것이 반드시 명시된 요구 사항을 충족한다는 것을 의미하지는 않습니다. 예를 들어, StartStop을 동일한 프로세서에서 실행해야하는 다중 프로세서 시스템에서는 신뢰할 수 없습니다. 상관 없지만, it does. 또한 시계 속도를 위아래로 조절할 수있는 프로세서의 경우 subject to being unreliable입니다. 그리고 심지어는 QueryPerformanceCounter에 대한 호출 자체가 현실적인 2+ GHz 프로세서에서도 약 5 마이크로 초 정도 걸리므로 실제로 이론에서 좋은 소리가 들리는 서브 마이크로 초 타이밍을 달성 할 수는 없습니다. 그런 다음 다시 합리적인 코드 프로파일 러는 시간의 양을 무시할 수 있다고 생각합니다. 왜냐하면 입니다.
(참조 : http://www.devsource.com/c/a/Techniques/High-Performance-Timing-under-Windows/2/)

+0

긴 설명해 주셔서 고맙습니다. 예를 들어, 실시간 OS를 사용한다면, 그런 종류의 고정밀 타이머를 사용할 수 있습니까? Windows 서버 실시간 OS입니까? 감사. –

+2

RTOS를 사용하는 경우 고해상도 타이머를 사용할 수 있습니다. 그러나 실시간 OS는 일이 즉시 일어나는 것을 의미하지는 않지만 알려진 시간 내에 발생한다는 것을 의미하므로 여전히 생각만큼 정확하게 시간을 정할 수 없습니다. Windows가 RTOS 인 것처럼, 확실히 아닙니다. –

+1

@publicENEMY : David Yaw의 답변이 정확합니다. 서버 버전의 Windows조차도 실시간 운영 체제가 아닙니다 (필자는 Windows Server를 워크 스테이션으로 운영합니다.별로 다르지 않습니다). OS에 의해 노출되는 소프트웨어 제한을 극복하더라도 일반적인 PC 하드웨어의 한계를 놓고 싸워야 할 필요가 있음을 지적 할 가치가 있습니다. OS 전환을 고려하고 있다면, 달성하려는 작업을 수행하는 더 좋은 방법이되어야합니다. –