簡體   English   中英

Thread.Sleep(1) 在 C# 中有什么影響?

[英]What is the impact of Thread.Sleep(1) in C#?

在 Windows 窗體應用程序中,調用Thread.Sleep(1)的影響是什么,如以下代碼所示:

public Constructor()
{
    Thread thread = new Thread(Task);
    thread.IsBackground = true;
    thread.Start();
}

private void Task()
{
    while (true)
    {
        // do something
        Thread.Sleep(1);
    }
}

這個線程會占用所有可用的 CPU 嗎?

我可以使用哪些分析技術來測量此線程的 CPU 使用率(任務管理器除外)?

如上所述,您的循環不會占用 CPU。

但請注意:Windows不是實時操作系統,因此您不會從 Thread.Sleep(1) 獲得每秒 1000 次喚醒。 如果您沒有使用timeBeginPeriod設置您的最小分辨率,您將每 15 毫秒喚醒一次。 即使您將最小分辨率設置為 1 毫秒,您仍然只能每 3-4 毫秒喚醒一次。

為了獲得毫秒級計時器粒度,您必須使用 Win32 多媒體計時器( C# 包裝器)。

不,它不會占用 CPU,它只會暫停您的線程至少那么長時間。 當您的線程暫停時,操作系統可以安排另一個不相關的線程來使用處理器。

Thread.Sleep(1) 如上所述不會占用 CPU。

以下是線程休眠(或多或少)時發生的情況:

  • Thread.Sleep 被翻譯成系統調用,進而觸發陷阱(允許操作系統控制的中斷)
  • 操作系統檢測到睡眠調用並將您的線程標記為阻塞。
  • 操作系統在內部保存了一個需要喚醒的線程列表以及它應該何時發生。
  • 由於線程不再使用 CPU,操作系統...
  • 如果父進程沒有用完它的所有時間片,操作系統將調度進程的另一個線程來執行。
  • 否則另一個進程(或空閑進程)將開始執行。
  • 當時間到期時,您的線程將再次被安排執行,這並不意味着它會自動開始執行。

最后一點,我不完全知道你在做什么,但看起來你正在嘗試扮演調度程序的角色,也就是說,睡眠為 CPU 提供時間做其他事情......

在少數情況下(確實很少)它可能沒問題,但大多數情況下你應該讓調度程序完成它的工作,它可能比你知道的更多,並且可以使工作比你做的更好

應該避免小的睡眠時間,因為放棄其時間片的線程在重新發出信號時會獲得優先級提升,這可能導致高上下文切換。 在多線程/服務器應用程序中,這可能會導致抖動效果,因為線程正在爭奪 CPU 時間。 相反,依靠異步函數和同步對象,例如臨界區或互斥體/信號量。

這是一個舊線程,在我的很多搜索中都會出現,但 Win7 有一個新的調度程序,並且其行為似乎與上述不同。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime dtEnd = DateTime.Now.AddSeconds(1.0);
            int i = 0;
            while (DateTime.Now < dtEnd)
            {
                i++;
                Thread.Sleep(1);
            }

            Console.WriteLine(i.ToString());

            i = 0;
            long lStart = DateTime.Now.Ticks;
            while (i++ < 1000)
                Thread.Sleep(1);

            long lTmp = (DateTime.Now.Ticks - lStart) / 10000;

            Console.WriteLine(lTmp.ToString());

            Console.Read();
        }
    }
}

使用上面的代碼,我的第一個結果給出了 946。所以在使用 1ms 睡眠的 1 秒時間跨度內,我得到了 946 次喚醒。 這非常接近 1ms。

第二部分詢問以 1ms 為單位執行 1000 個睡眠事件需要多長時間。 我得到了 1034 毫秒。 同樣,將近1ms。

這是在使用 .Net 4.0 的 1.8ghz core2duo + Win7 上

編輯:記住,sleep(x) 並不意味着此時醒來,它意味着不早於這個時間喚醒我。 不能保證。 雖然,您可以增加線程的優先級,並且 Windows 應該在較低優先級的線程之前安排您的線程。

正如 Bob Nadler 提到的Thread.Sleep(1)不保證 1ms 的睡眠時間。

下面是一個使用 Win32 多媒體計時器強制休眠 1 毫秒的示例。

    [DllImport("winmm.dll")]
    internal static extern uint timeBeginPeriod(uint period);
    [DllImport("winmm.dll")]
    internal static extern uint timeEndPeriod(uint period);

    timeBeginPeriod(1);
    while(true)
    {
        Thread.Sleep(1); // will sleep 1ms every time
    }
    timeEndPeriod(1);

在 C# GUI 應用程序中對此進行測試,我發現該應用程序使用了大約 50% 的 CPU。

有關此主題的更多討論,請參閱以下論壇主題:

http://www.dotnet247.com/247reference/msgs/57/289291.aspx

不,它不會占用所有可用的 CPU,因為當另一個線程有工作要做時,操作系統的調度程序將關閉一個睡眠線程。

不,不會。 你幾乎看不到它。 在每秒不到 1000 次的某個地方,這個線程會醒來,在再次睡覺之前幾乎什么都不做。

編輯:

我不得不檢查。 在 Java 1.5 上運行,此測試

@Test
public void testSpeed() throws InterruptedException {
    long currentTime = System.currentTimeMillis();
    int i = 0;
        while (i < 1000)
        {
            Thread.sleep(1);
            i++;
        }
    System.out.println("Executed in " + (System.currentTimeMillis() - currentTime));
}

在我的 3ghz 機器上以每秒大約 500 個睡眠的速度運行。 我想 C# 應該大致相同。 我假設有人會為這個非常重要的現實世界基准報告 C# 數字。 順便說一下,沒有可觀察到的 CPU 使用率。

一個線程一次最多可以占用一個(邏輯)CPU。 並且 1 毫秒的睡眠不會占用大量資源。 不要出汗。

也看看這個: msdn論壇

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;

namespace Test
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            Stopwatch sw = new Stopwatch();

            for (int i = 0; i < 10; ++i)
            {
                sw.Reset();
                sw.Start();
                Thread.Sleep(50);
                sw.Stop();

                Console.WriteLine("(default) Slept for " + sw.ElapsedMilliseconds);

                TimeBeginPeriod(1);
                sw.Reset();
                sw.Start();
                Thread.Sleep(50);
                sw.Stop();
                TimeEndPeriod(1);

                Console.WriteLine("(highres) Slept for " + sw.ElapsedMilliseconds + "\n");
            }
        }

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM