Come faccio a mettere in pausa il mio programma C # per 50 msec?


272

Come faccio a far dormire il mio programma C # per 50 millisecondi?

Potrebbe sembrare una domanda facile, ma sto vivendo un momento temporaneo di insufficienza cerebrale!


1
Taggato nuovamente su VB.NET perché la risposta funziona anche lì.
DrFloyd5,

No DrFloyd5,; non funziona su VB.NET, giusto?
Zanoni,

16
Se fossi nel team VB.Net, aggiungerei; come personaggio commento alla prossima versione della lingua ...
Joel Coehoorn,

4
Penso che i programmatori VB siano abbastanza brillanti da capire l'equivalente ..
BlueRaja - Danny Pflughoeft

bene, solo per essere sicuri, ora non è necessario.
PsychoData,

Risposte:


330
System.Threading.Thread.Sleep(50);

Ricorda però che farlo nel thread della GUI principale bloccherà l'aggiornamento della tua GUI (sembrerà "lenta")

Basta rimuovere il ;per farlo funzionare anche per VB.net.


Dopo aver chiamato sleep in un metodo, il programma continuerà a essere eseguito in background (senza creare un nuovo thread)? Inoltre, se chiamo sleep in un nuovo thread, il thread principale continuerà a funzionare?
Jay Nirgudkar,

@JayNirgudkar il thread che chiama Sleep verrà interrotto. Gli altri thread non sono interessati.
Isak Savo,

Questo non è garantito per essere accurato.
Akumaburn,

150

Esistono sostanzialmente 3 opzioni per l'attesa in (quasi) qualsiasi linguaggio di programmazione:

  1. Attesa libera
    • Esecuzione di blocchi di thread per un determinato tempo (= non consuma potenza di elaborazione)
    • Non è possibile l'elaborazione sul thread bloccato / in attesa
    • Non così preciso
  2. Attesa stretta (chiamata anche anello stretto)
    • il processore è MOLTO occupato per l'intero intervallo di attesa (infatti, di solito consuma il 100% del tempo di elaborazione di un core)
    • Alcune azioni possono essere eseguite durante l'attesa
    • Molto preciso
  3. Combinazione di 2 precedenti
    • Di solito combina l'efficienza di elaborazione di 1. e la precisione + capacità di fare qualcosa di 2.

per 1. - Attesa libera in C #:

Thread.Sleep(numberOfMilliseconds);

Tuttavia, l'utilità di pianificazione dei thread di Windows determina una precisione di Sleep()circa 15 ms (quindi Sleep può facilmente attendere 20 ms, anche se è pianificato di attendere solo 1 ms).

per 2. - L'attesa stretta in C # è:

Stopwatch stopwatch = Stopwatch.StartNew();
while (true)
{
    //some other processing to do possible
    if (stopwatch.ElapsedMilliseconds >= millisecondsToWait)
    {
        break;
    }
}

Potremmo anche usare DateTime.Nowo altri mezzi di misurazione del tempo, ma Stopwatchè molto più veloce (e questo diventerebbe davvero visibile in un circuito chiuso).

per 3. - Combinazione:

Stopwatch stopwatch = Stopwatch.StartNew();
while (true)
{
    //some other processing to do STILL POSSIBLE
    if (stopwatch.ElapsedMilliseconds >= millisecondsToWait)
    {
        break;
    }
    Thread.Sleep(1); //so processor can rest for a while
}

Questo codice blocca regolarmente il thread per 1 ms (o leggermente più, a seconda della pianificazione dei thread del sistema operativo), quindi il processore non è occupato per quel periodo di blocco e il codice non consuma il 100% della potenza del processore. Altre elaborazioni possono ancora essere eseguite tra i blocchi (come: aggiornamento dell'interfaccia utente, gestione degli eventi o attività di interazione / comunicazione).


1
Il timer potrebbe anche essere di interesse
JonnyRaa,

55

Non è possibile specificare un tempo di sospensione esatto in Windows. Per questo è necessario un sistema operativo in tempo reale. Il meglio che puoi fare è specificare un tempo di sonno minimo . Dopodiché tocca allo scheduler riattivare il thread. E non chiamare mai.Sleep() il thread della GUI.


44

Poiché ora hai la funzione asincroni / attendi, il modo migliore per dormire per 50ms è usare Task.Delay:

async void foo()
{
    // something
    await Task.Delay(50);
}

Oppure, se stai utilizzando come target .NET 4 (con Async CTP 3 per VS2010 o Microsoft.Bcl.Async), devi utilizzare:

async void foo()
{
    // something
    await TaskEx.Delay(50);
}

In questo modo non bloccherai il thread dell'interfaccia utente.


puoi response.flush durante questo ritardo, se è in un ciclo?
Teoman Shipahi,

No, non puoi. Credo che ci sia una FlushAsyncversione.
Toni Petrina,

6
Un'alternativa che non richiede una asyncdichiarazione è quella di chiamareTask.Delay(50).Wait();
stuartd il


14
Thread.Sleep(50);

Il thread non verrà pianificato per l'esecuzione dal sistema operativo per il periodo di tempo specificato. Questo metodo modifica lo stato del thread per includere WaitSleepJoin.

Questo metodo non esegue il pompaggio COM e SendMessage standard. Se è necessario dormire su un thread con STAThreadAttribute, ma si desidera eseguire il pumping COM e SendMessage standard, prendere in considerazione l'utilizzo di uno dei sovraccarichi del metodo Join che specifica un intervallo di timeout.

Thread.Join


0

A partire da .NET Framework 4.5, è possibile utilizzare:

using System.Threading.Tasks;

Task.Delay(50).Wait();   // wait 50ms

-1

Il meglio di entrambi i mondi:

using System.Runtime.InteropServices;

    [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
    private static extern uint TimeBeginPeriod(uint uMilliseconds);

    [DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
    private static extern uint TimeEndPeriod(uint uMilliseconds);
    /**
     * Extremely accurate sleep is needed here to maintain performance so system resolution time is increased
     */
    private void accurateSleep(int milliseconds)
    {
        //Increase timer resolution from 20 miliseconds to 1 milisecond
        TimeBeginPeriod(1);
        Stopwatch stopwatch = new Stopwatch();//Makes use of QueryPerformanceCounter WIN32 API
        stopwatch.Start();

        while (stopwatch.ElapsedMilliseconds < milliseconds)
        {
            //So we don't burn cpu cycles
            if ((milliseconds - stopwatch.ElapsedMilliseconds) > 20)
            {
                Thread.Sleep(5);
            }
            else
            {
                Thread.Sleep(1);
            }
        }

        stopwatch.Stop();
        //Set it back to normal.
        TimeEndPeriod(1);
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.