C#プログラムを50ミリ秒間スリープさせるにはどうすればよいですか?


272

C#プログラムを50ミリ秒間スリープさせるにはどうすればよいですか?

これは簡単な質問のように思えるかもしれませんが、私は一時的な脳の障害の瞬間を抱えています!


1
回答も同様に機能するため、VB.NETにタグを付け直しました。
DrFloyd5 2009

DrFloyd5なし; VB.NETでは機能しませんか?
Zanoni

16
VB.Netチームに所属している場合は、を追加します。言語の次のバージョンへのコメント文字として...
Joel Coehoorn、

4
私は、VBプログラマは同等の把握に十分に明るいと思います...
BlueRaja -ダニーPflughoeft

まあ、念のために言っておきますが、今はそうする必要はありません。
PsychoData 2014

回答:


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

ただし、メインGUIスレッドでこれを行うと、GUIの更新がブロックされることを覚えておいてください(「緩慢」に感じる)

;VB.netでも機能するように削除するだけです。


メソッドでスリープを呼び出した後、プログラムは(新しいスレッドを作成せずに)バックグラウンドで実行し続けますか?また、新しいスレッドでスリープを呼び出した場合、メインスレッドは作業を続行しますか?
Jay Nirgudkar、2015

@JayNirgudkarは、Sleepを呼び出すスレッドを停止します。他のスレッドは影響を受けません。
Isak Savo

これは正確であることが保証されていません。
Akumaburn 2016年

150

(ほぼ)すべてのプログラミング言語で待機するには、基本的に3つの選択肢があります。

  1. ゆるい
    • 一定時間スレッドブロックを実行する(=処理能力を消費しない)
    • ブロックされた/待機中のスレッドでは処理できません
    • それほど正確ではない
  2. タイトウェイティング(タイトループとも呼ばれます)
    • プロセッサは待機間隔全体で非常にビジーです(実際、通常は1つのコアの処理時間の100%を消費します)
    • 待機中に実行できるアクションがあります
    • 非常に正確
  3. 前の2つの 組み合わせ
    • 通常、1の処理効率と2の何かを実行するための精度+能力を組み合わせます。

for 1.-C#での緩やかな待機:

Thread.Sleep(numberOfMilliseconds);

ただし、Windowsスレッドスケジューラの精度はSleep()約15ミリ秒です(したがって、1ミリ秒だけ待機するようにスケジュールされている場合でも、スリープは簡単に20ミリ秒待機できます)。

for 2-C#でのタイトな待機は次のとおりです。

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

DateTime.Now時間測定のその他の手段を使用することもできますStopwatchが、はるかに高速です(これは、タイトループで実際に表示されます)。

3.の組み合わせ:

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
}

このコードは定期的にスレッドを1ミリ秒(またはOSスレッドのスケジューリングによってはそれ以上)ブロックします。そのため、そのブロックの間プロセッサはビジーではなく、コードはプロセッサの電力を100%消費しません。その他の処理は、ブロックの間に実行することもできます(UIの更新、イベントの処理、対話/通信など)。


1
タイマーも興味深いかもしれません
JonnyRaa

55

Windowsでは正確なスリープ時間を指定することはできません。そのためにはリアルタイムOSが必要です。最善の方法は、最小スリープ時間を指定することです。その後、スケジューラーがスレッドをウェイクアップするかどうかが決まります。また、GUIスレッドを呼び出さないでください.Sleep()


44

これで非同期/待機機能が利用できるようになったので、50ms間スリープする最善の方法はTask.Delayを使用することです。

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

または、.NET 4(VS2010の非同期CTP 3またはMicrosoft.Bcl.Asyncを使用)をターゲットにしている場合は、以下を使用する必要があります。

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

このようにして、UIスレッドをブロックしません。


ループしている場合、この遅延中にresponse.flushを実行できますか?
Teoman Shipahi 2013

いいえ、あなたがすることはできません。FlushAsyncバージョンがあると思います。
Toni Petrina

6
async宣言を必要としない別の方法は、電話をかけることですTask.Delay(50).Wait();
stuartd


14
Thread.Sleep(50);

スレッドは、指定された時間、オペレーティングシステムによる実行がスケジュールされません。このメソッドは、スレッドの状態を変更して、WaitSleepJoinを含めます。

このメソッドは、標準のCOMおよびSendMessageポンプを実行しません。STAThreadAttributeを持つスレッドでスリープする必要があるが、標準のCOMおよびSendMessageポンプを実行する場合は、タイムアウト間隔を指定するJoinメソッドのオーバーロードの1つを使用することを検討してください。

Thread.Join


0

.NET Framework 4.5以降では、次のものを使用できます。

using System.Threading.Tasks;

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

-1

両方の長所:

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);
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.