C#中的三种timer
轉(zhuǎn)
https://blog.csdn.net/hoiven/article/details/51362582
如果你需要使用規(guī)律的時間間隔重復(fù)執(zhí)行一些方法,最簡單的方式是使用定時器(timer)。
.NET Framework 提供了 4 種定時器。下邊兩個類是通用的多線程定時器:
(1)System.Threading.Timer
(2)System.Timers.Timer
另外兩個是專用的單線程定時器:
(3)System.Windows.Forms.Timer (Windows Forms 的定時器)
(4)System.Windows.Threading.DispatcherTimer (WPF 的定時器)
多線程定時器更加強大、精確并且更加靈活,而單線程定時器對于一些簡單的更新 Windows Forms 和 WPF 控件的任務(wù)來說是安全的,并且更加便捷。
1.多線程定時器
System.Threading.Timer是最簡單的多線程定時器:它僅僅有一個構(gòu)造方法和兩個普通方法(取悅于極簡主義者,還有本書作者!)。在接下來的例子中,一個定時器在 5 秒鐘之后調(diào)用Tick方法來打印 “ tick… “,之后每秒打印一次直到用戶按下回車鍵:
using System; using System.Threading;class Program {static void Main(){// 首次間隔 5000ms,之后間隔 1000msTimer tmr = new Timer (Tick, "tick...", 5000, 1000);Console.ReadLine();tmr.Dispose(); // 停止定時器并執(zhí)行清理工作 }static void Tick (object data){// 這里運行在一個線程池線程上Console.WriteLine (data); // 打印 "tick..." } }之后可以通過調(diào)用Change方法來改變定時器的時間間隔。如果你希望定時器只觸發(fā)一次,可以指定Timeout.Infinite作為構(gòu)造方法的最后一個參數(shù)。
2、.NET Framework 在System.Timers命名空間下提供了另一個名字相同的定時器類。它只是封裝了 System.Threading.Timer,并在使用完全相同的底層引擎的前提下提供額外的便利。下面是增加功能的簡介:
(1)實現(xiàn)了Component,允許用于 Visual Studio 的設(shè)計器中。
(2)Interval屬性代替了Change方法。
(3)Elapsed事件代替了回調(diào)委托。
(4)Enabled屬性用于開始或停止定時器(默認值是false)。
(5)Start和Stop方法,避免對Enabled屬性感到困惑。
(6)AutoReset標(biāo)識來指定是否為可重復(fù)的事件(默認為true)。
SynchronizingObject屬性提供Invoke和BeginInvoke方法,用于在 WPF 和 Windows Forms 控件上安全調(diào)用方法。
多線程定時器使用線程池來允許少量線程服務(wù)多個定時器。這意味著,回調(diào)方法或Elapsed事件每次可能會在不同的線程上觸發(fā)。此外,不論之前的Elapsed是否完成執(zhí)行,Elapsed總是幾乎按時觸發(fā)。因此,回調(diào)方法或事件處理器必須是線程安全的。
多線程定時器的精度依賴于操作系統(tǒng),通常是在 10-20 ms 的區(qū)間。如果需要更高的精度,你可以使用本地互操作(native interop)來調(diào)用 Windows 多媒體定時器,可以讓精度提升到 1 ms。它定義在 winmm.dll 中,首先調(diào)用timeBeginPeriod來通知操作系統(tǒng)你需要更高的定時器精度,然后調(diào)用timeSetEvent來啟動多媒體定時器。當(dāng)使用完成后,調(diào)用timeKillEvent停止定時器,最后調(diào)用timeEndPeriod通知操作系統(tǒng)你不在需要更高的定時器精度了。可以通過搜索關(guān)鍵字 dllimport winmm.dll timesetevent 在網(wǎng)上找到完整的例子。
3、它們暴露的成員都像System.Timers.Timer一樣(Interval、Tick、Start和Stop),并且用法也類似。但是不同之處在于其內(nèi)部是如何工作的。它們不是使用線程池來產(chǎn)生定時器事件,WPF 和 Windows Forms 定時器依賴于 UI 模型的底層消息循環(huán)機制(message pumping mechanism)。意味著Tick事件總是在創(chuàng)建該定時器的那個線程觸發(fā),在通常的程序中,它也就是管理所有 UI 元素和控件的那個線程。
單線程計時器比較安全,對于更新 Windows Forms controls或者WPF這種簡單任務(wù)來說更方便。在WPF或Windows Forms中安全的調(diào)用方法的SynchronizingObject對象。
單線程計時器是被設(shè)計成屬于他們執(zhí)行環(huán)境的計時器,如果你在一個Windows服務(wù)應(yīng)用程序中使用Windows Forms的Timer,timer 事件并不會被觸發(fā),只有在對應(yīng)的環(huán)境下才會被觸發(fā)。
像System.Timers.Timer一樣,他們也提供了相同的成員(Interval,Tick,Start,Stop),但是他們內(nèi)部的工作原理不同,WPF和Windows Forms的計時器使用消息循環(huán)機制來取代線程池產(chǎn)生消息的機制。
你可以不必考慮線程安全。
新的Tick在之前的Tick完成執(zhí)行前不會觸發(fā)。
你可以直接在Tick時間事件的處理代碼中更新 UI 控件,而不需要調(diào)用Control.Invoke或Dispatcher.Invoke。
這聽起來好的難以置信,直到你意識到使用這些定時器的程序并不是真正的多線程,不會有并行執(zhí)行。一個線程服務(wù)于所有定時器,并且還處理 UI 事件。這帶來了單線程定時器的缺點:
除非Tick事件處理器執(zhí)行的很快,否則 UI 會失去響應(yīng)。
這使得 WPF 和 Windows Forms 定時器僅適用于小任務(wù),通常就是那些更新 UI 外觀的任務(wù)(例如,顯示時鐘或倒計時)。否則,你就需要多線程定時器。
在精度方面,單線程定時器與多線程定時器類似(幾十毫秒),但是通常精度更低,因為它們會被其它 UI 請求(或其它定時器事件)推遲。
單線程計時器基于Windows消息循環(huán),應(yīng)用程序會同步的處理計時器的消息。會發(fā)現(xiàn)UI界面相應(yīng)速度比較慢。解決這個問題的方法是使用多線程計時器。
單線程計時器的缺點:除非Tick事件的處理代碼執(zhí)行的非常快,否則UI界面會變得響應(yīng)很慢。所以 WPF和Windows Forms的計時器都非常適合小任務(wù),尤其是界面更新的任務(wù)。例如時鐘和計數(shù)顯示。否則,你需要一個多線程計時器
用法舉例
System.Timers.Timer是多線程定時器,如果一個Timer沒有處理完成,到達下一個時間點,新的Timer同樣會被啟動,所以在使用Timer時需要注意,當(dāng)設(shè)定的時間間隔遠大于任務(wù)時間時,能夠?qū)崿F(xiàn)只在一個線程中執(zhí)行,但是不能確保一定是一個。
https://blog.csdn.net/yl2isoft/article/details/51346469
如何prevent System.Timers.Timer的觸發(fā)事件從一個線程池排隊來執(zhí)行?(How to prevent System.Timers.Timer from queuing for execution on a thread pool?)
There is a problem with standard System.Timers.Timer behaviour. The timer raise Elapsed event with some interval. But when time of execution inside Elapsed event handler exceed timer interval then thread pool begin queuing event handling. This is a problem in my case. This is because with my Elapsed event handler I fetch some data from database and doing something with it and finally save results back to database. But data handling should be provided only once. So, is there a way to prevent from queuing elapse events for System.Timers.Timer.(怎樣只讓事件執(zhí)行一次)
As illustration for this issue you can consider next test program:
public class EntryPoint {private static void TimeProc(object state, ElapsedEventArgs e){Console.WriteLine("Current time {0} on the thread {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId);Thread.Sleep(20000);}static void Main(string[] args){Console.WriteLine("Press <Enter> for finishing\n\n");ThreadPool.SetMaxThreads(10, 10);System.Timers.Timer MyTimer = new System.Timers.Timer(1000);MyTimer.Elapsed += new ElapsedEventHandler(TimeProc);MyTimer.Start();Console.ReadLine();MyTimer.Stop();} }解決方法:
public class EntryPoint{private static System.Timers.Timer MyTimer;private static void TimeProc(object state, ElapsedEventArgs e){Console.WriteLine("Current time {0} on the thread {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId);Thread.Sleep(20000); MyTimer.Enabled = true;}static void Main(string[] args){Console.WriteLine("Press <Enter> for finishing\n\n");ThreadPool.SetMaxThreads(10, 10);MyTimer = new System.Timers.Timer(1000); MyTimer.AutoReset = false;MyTimer.Elapsed += new ElapsedEventHandler(TimeProc); MyTimer.Enabled = true;Console.ReadLine();}}以上方法似乎不行,不知道有什么能夠確保只在一個線程中執(zhí)行觸發(fā)函數(shù)的方法。
https://www.cnblogs.com/dotnet261010/p/7113523.html
https://www.cnblogs.com/yang-fei/p/6169089.html
?
轉(zhuǎn)載于:https://www.cnblogs.com/janghe/p/8981282.html
總結(jié)
以上是生活随笔為你收集整理的C#中的三种timer的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 利用ASP.netCore自带DI(De
- 下一篇: OO第二次作业总结