2010-11-18 14 views
15

Desidero utilizzare il timer di risoluzione più alto possibile utilizzando C#. Per esempio, voglio aumentare un evento ogni 11 tick (ho sentito che tick è il contatore più alto possibile nel pc). Ho provato il timer e ho scoperto che il tempo minimo trascorso è in millisecondi. guardato il cronometro ma il cronometro non aumenta gli eventi.Evento evento in intervallo/temporizzatore ad alta risoluzione

Grazie.

+2

Perché in tutto il mondo vorresti organizzare un evento ogni 11 tick? Stai usando questo per il profiling del codice? –

+5

Non stai rispondendo alle domande. 11 tick è solo un esempio. tutto quello che voglio è il timer ad alta risoluzione. se possibile, fino a 1 tick. e sì, sto sviluppando un'applicazione per fare qualche punto di riferimento. –

+0

Questo è il motivo per cui supporto i commenti in downvoting –

risposta

18

L'utilizzo di un timer multimediale dovrebbe fornire circa 1000 eventi al secondo. Questo codice dovrebbe aiutarti per strada.

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

Arrestare questi timer dopo averli eseguiti. Sono piuttosto pesanti sul tuo sistema *. Prendi tutte le eccezioni e non lasciare che sfuggano al tuo gestore di eventi.

* L'avvio di più di 5 timer rallenterà notevolmente la maggior parte dei sistemi! Esegui il minor numero possibile di codice nei gestori di eventi e assicurati che il codice di esecuzione sia più veloce di 1 millisecondo o faccia fronte a problemi gravi. Ho avviato un delegato ogni 10-50 tick per aumentare la visualizzazione dell'etichetta.

Un normale interruttore di thread che si verifica su un Thread.Sleep lascerà uno slot di thread libero dal codice e richiederà circa 40 millisecondi. È anche possibile aumentare la frequenza di cambio thread con alcune chiamate al kernel NT, ma per favore, non farlo.

4

Le varie classi di timer utilizzano una granularità maggiore. Entrambi Threading.Timer e Timers.Timer utilizzano 1/64 di secondo, ovvero 15,66 millisecondi.

Se il "segno di spunta" a cui ci si riferisce è il tick da 100 nanosecondi, utilizzato dalla classe DateTime, classe TimeSpan e prodotto dal cronometro, la lunghezza di 11 tick richiesta è di 1.100 nanosecondi, oppure 1,1 microsecondi. Per quanto ne so, non esiste un timer integrato che ti dia questa risoluzione. Se vuoi davvero che si verifichi un evento ogni 1,1 microsecondi, dovrai rimuovere l'idea di un "timer" e pensare invece in termini di un breve ritardo. Aumenta la priorità di un thread ed esegui il tuo evento in un ciclo. Non chiamare Thread.Sleep(), poiché credo che 1,1 microsecondi siano inferiori al timeslice del programma di pianificazione. Dovrai invece fare un ciclo di ritardo.

Inoltre, renditi conto che l'intervallo di tempo che stai chiedendo è molto, molto piccolo. 1,1 microsecondi sono solo 2.200 cicli di processore su un processore a 2 GHz. Non un importo insignificante, ma non molto tempo per fare molto lavoro. Se stai parlando dell'1 tick che hai detto nel tuo commento, sono solo 200 cicli del processore: è abbastanza tempo per fare alcune decine di operazioni matematiche e forse chiamare una funzione.

+0

Il segno di spunta che mi interessa è il tick di cronometro. In altre parole, tick ciclo del processore. –

+3

Tick del ciclo del processore, ad es. 2 GHz? Quello è 0,5 nanosecondi. Tutti tranne le più semplici istruzioni del processore richiedono più cicli del processore. Ad esempio, potresti essere in grado di incrementare un intero in un ciclo, ma un'istruzione 'if'? In nessun modo, è nell'ordine di 10 cicli del processore, 5 nanosecondi. Non c'è modo di controllare un timer a quella frequenza, tanto meno ottenere un lavoro. –

+4

Aspetta, lo riprendo. C'è un modo per avere un timer con una frequenza di 1 ciclo del processore: Impostare il thread su priorità alta e fare 'while (true) {...}' –

14

Prima di tutto, è necessario rendersi conto che è estremamente difficile, se non impossibile, eseguire i tempi esatti su un computer a causa delle limitazioni esposte sia dall'hardware che dal software. La buona notizia è che questo tipo di precisione è raramente necessario. Dieci tick è un follemente piccolo quantità di tempo. In questo intervallo il lavoro svolto dalla CPU in questo intervallo è molto limitato e non sarà mai statisticamente significativo.

Per riferimento, l'orologio di Windows ha una precisione di circa 10 millisecondi (meno rispetto alle versioni precedenti). Avvolgere il tuo codice con le chiamate a DateTime.UtcNow non funzionerà meglio di così.

Nella tua domanda parli di voler "creare un evento". Il problema è che l'unico tipo di oggetto di mantenimento del tempo che solleva un evento a intervalli specifici è l'oggetto Timer. È disponibile in 3 diverse incarnazioni in .NET Framework (System.Timers.Timer, System.Threading.Timer e System.Windows.Forms.Timer), ognuna con scenari di utilizzo unici e peculiarità relative, ma nessuna di queste garantisce precisione ovunque vicino a ciò che si sta chiedendo per . Non sono nemmeno progettati per farlo, né esistono funzioni equivalenti esposte dall'API di Windows che forniranno questo tipo di precisione.

La ragione per cui ho chiesto il motivo per cui si desidera eseguire questa operazione e se si sta tentando di eseguire un benchmark è perché questo cambia l'intero gioco. .NET Framework (dalla versione 2.0) fornisce uno Stopwatch object espressamente progettato per misurare con precisione il tempo trascorso per una situazione come il benchmarking o il profiling delle prestazioni. Lo Stopwatch avvolge semplicemente le funzioni API di Windows QueryPerformanceFrequency e QueryPerformanceCounter (che dovrebbe confermare il mio suggerimento sull'uso previsto). Avevamo bisogno di P/Richiamare queste funzioni per accedere a questo tipo di funzionalità nelle versioni precedenti del Framework, ma ora è comodamente integrato. Se hai bisogno di un timer con una risoluzione relativamente alta per il benchmarking, lo Stopwatch è la soluzione migliore . In teoria, può fornire tempi di sottosecondo.

Ma non è privo di problemi. Non genera alcun evento, quindi se il tuo progetto attuale si basa sulla gestione degli eventi, dovrai ripensarlo. E, , non è garantito che sia perfettamente preciso. Certo, potrebbe avere la risoluzione più alta possibile dato i vincoli hardware, ma ciò non significa che soddisferà necessariamente i requisiti dichiarati. Ad esempio, potrebbe non essere affidabile su un sistema con più processori in cui è necessario eseguire Start e Stop sullo stesso processore. Non dovrebbe essere importante, ma it does. È anche subject to being unreliable sui processori che possono accelerare e ridurre la velocità di clock. E oserei anche ricordare che la chiamata allo QueryPerformanceCounter richiederà un po 'di tempo - circa 5 microsecondi anche su un moderno processore 2+ GHz, che ti impedisce di essere effettivamente in grado di raggiungere quel tempo di sottosecondo che suonava bene in teoria. Inoltre, qualsiasi profiler di codice ragionevole considererebbe trascurabile quella quantità di tempo perché, beh, è.
(Vedi anche: http://www.devsource.com/c/a/Techniques/High-Performance-Timing-under-Windows/2/)

+0

Grazie per la spiegazione lunga. se, ad esempio, utilizzo il sistema operativo in tempo reale, posso ottenere quel tipo di timer ad alta precisione? Windows Server è un sistema operativo in tempo reale? Grazie. –

+2

Se si utilizza un RTOS, si potrebbe avere la possibilità di un timer ad alta risoluzione. Tuttavia, un OS in tempo reale non significa che le cose accadono immediatamente, ma che avvengono entro un limite di tempo noto, quindi potresti non essere in grado di calcolare il tempo così preciso come stai pensando. Per quanto riguarda Windows è un RTOS, decisamente no. –

+1

@publicENEMY: la risposta di David Yaw è corretta. Anche le versioni Server di Windows non sono sistemi operativi in ​​tempo reale (eseguo Windows Server come workstation, non è poi così tanto diverso). Vale anche la pena ricordare che anche se hai superato le limitazioni del software esposte dal sistema operativo, dovrai comunque fare i conti con i limiti dell'hardware del PC comune. Se stai pensando di cambiare sistema operativo, lì * deve * essere un modo migliore per fare ciò che stai cercando di ottenere. –

Problemi correlati