2010-05-12 76 views
43

在我的應用程序中,我必須定期發送心跳到「兄弟」應用程序。System.Timers.Timer/Threading.Timer與線程與WhileLoop + Thread.Sleep定期任務

使用System.Timers.Timer/Threading.Timer或使用帶有while循環和Thread.Sleep的線程可以更好地完成嗎?

心跳間隔爲1秒。

while(!exit) 
{ 
    //do work 
    Thread.Sleep(1000); 
} 

myTimer.Start(() => { 
         //do work 
         }, 1000); //pseudo code (not actual syntax)... 

回答

32

System.Threading.Timer有我的投票。

System.Timers.Timer用於基於服務器(您的代碼作爲主機上的服務器/服務運行,而不是由用戶運行)計時器功能。

考慮到在.NET中存在更健壯的Timer mecahnisms,帶有While循環和Thread.Sleep命令的線程確實是一個壞主意。

+2

你有我的。 – Alan 2010-05-12 20:18:54

+2

@Alan:你有我的 – abatishchev 2010-05-12 20:28:27

+3

System.Timers.Timer類真的可以像System.Threading.Timer一樣在用戶模式應用程序中使用。在內部,System.Timers.Timer使用System.Threading.Timer作爲它的內部時間機制,並且只包裝它來處理設計時間問題。 – 2010-05-12 20:46:36

22

Server Timers是不同於睡眠線程的生物。

首先,根據您的線程的優先級以及還有哪些正在運行,您的睡眠線程可能會或不會被喚醒並按您要求的時間間隔運行。如果間隔足夠長,並且調度的精度並不重要,那麼Thread.Sleep()是合理的選擇。

另一方面,定時器可以在任何線程上提升事件,從而提供更好的調度功能。然而,使用定時器的代價在代碼中稍微複雜一些 - 而且事實上你可能無法控制哪個線程運行定時器事件觸發的邏輯。從文檔:基於服務器

定時器是專爲 在 多線程環境中工作線程使用。服務器 定時器可以在線程間移動到 處理提升的Elapsed事件, 導致比 更高的準確性提高 事件的時間。

另一個考慮因素是計時器在ThreadPool線程上調用它們的Elapsed委託。根據邏輯的耗時和/或複雜程度,您可能不希望在線程池上運行它 - 您可能需要一個專用線程。定時器的另一個因素是,如果處理時間足夠長,定時器事件可能會在另一個線程中同時再次發生(如果正在運行的代碼不是爲了併發而設計或構造的,則這可能會造成問題)。

不要混淆服務器計時器與 「Windows Timers」。後者通常是指WM_TIMER消息可以傳遞給一個窗口,允許應用程序調度並響應其主線程上的定時處理,而無需休眠。但是,Windows定時器也可以參考Win API for low-level timing(與WM_TIMER不同)。

+0

感謝您的回答。我有點在「服務器計時器」和「Windows計時器」之間有點混淆,以及它與System.Threading.Timer和Thread.Sleep之間的關係。 – Alan 2010-05-12 20:21:08

+1

好的,System.Timers.Timer是一個服務器計時器。疑難雜症! – Alan 2010-05-12 20:22:58

+0

總的來說,浪費一個完全可以睡覺的完整線程是一個壞主意。線程是重量級的,最好使用基於ThreadPool的替代方法之一。 – 2012-12-11 00:00:51

20

無論:)

睡眠通常是令人難以接受的(可惜我不記得細節,但對一個,這是一個uninteruptible「塊」),並Timer小號配備了大量的行李。如果可能的話,我會建議System.Threading.AutoResetEvent這樣

// initially set to a "non-signaled" state, ie will block 
// if inspected 
private readonly AutoResetEvent _isStopping = new AutoResetEvent (false); 

public void Process() 
{ 
    TimeSpan waitInterval = TimeSpan.FromMilliseconds (1000); 

    // will block for 'waitInterval', unless another thread, 
    // say a thread requesting termination, wakes you up. if 
    // no one signals you, WaitOne returns false, otherwise 
    // if someone signals WaitOne returns true 
    for (; !_isStopping.WaitOne (waitInterval);) 
    { 
     // do your thang! 
    } 
} 

使用一個AutoResetEvent(或者其表弟ManualResetEvent)保證了與線程安全的信號真正的塊(這樣的事情如上正常終止)。在最壞的情況,它是Sleep

希望這有助於:)

+0

我喜歡它,乾淨地關閉你的線程的能力很好。 – 2010-05-12 20:33:00

+6

爲什麼一個for循環而不是while? – gav 2010-08-03 14:55:33

+2

@gav,'while'同樣適用,'for'是一種風格偏好。 – 2010-08-03 16:31:35

1

我發現,實際上縮放僅限於定時器實現System.Threading.Timer一個更好的選擇。如果你正在處理一個不重要的預定項目數量,所有其他的實現看起來很不真實。