C# System.Threading.Timer 与 System.Timers.Timer 的一点点区别
先说一下结论:差不多。
我目前明显感受到的唯一的差别是,Timers.Timer 的启动时,先要等一个 interval 时间,才触发 Timers.Timer.ElapsedEventHandler。
而 Threading.Timer,可以做到先触发它的 TimedCallback,再等一个 period 时间(类似 Timers.Timer 的 interval),再触发下一次 TimedCallback。当然,如果修改其 dueTime 为 period 的值,可以达到像 Timers.Timer 的行为。
另外感觉 Threading.Timer 更轻一点点点点,同样大家都是先等500ms再触发情况下,好像 Threading.Timer 会多触发一次 TimedCallback。
这个给个简单例子与结果:
using System; using System.Diagnostics; using System.Threading; namespace ConsoleApplication1 { class UnSafeTimer { static int i = 0; static System.Threading.Timer timer; static object mylock = new object(); static int sleep; static bool flag; public static Stopwatch sw = new Stopwatch(); static void Excute(object obj) { Console.WriteLine("Excute() current thread id = {0}/{1}", System.Threading.Thread.CurrentThread.ManagedThreadId,AppDomain.GetCurrentThreadId()); Thread.CurrentThread.IsBackground = false; int c; lock (mylock) { i++; c = i; } if (c == 80) { timer.Dispose();//执行Dispose后Timer就不会再申请新的线程了,但是还是会给Timmer已经激发的事件申请线程 sw.Stop(); } if (c < 80) Console.WriteLine("Now:" + c.ToString()); else { Console.WriteLine("Now:" + c.ToString() + "-----------Timer已经Dispose耗时:" + sw.ElapsedMilliseconds.ToString() + "毫秒"); } if (flag) { Thread.Sleep(sleep);//模拟花时间的代码 } else { if (i <= 80) Thread.Sleep(sleep);//前80次模拟花时间的代码 } } public static void Init(int p_sleep, bool p_flag) { Console.WriteLine("Init() current thread id = {0}/{1}", System.Threading.Thread.CurrentThread.ManagedThreadId,AppDomain.GetCurrentThreadId()); sleep = p_sleep; flag = p_flag; timer = new System.Threading.Timer(Excute, null, 0, 10); } } class SafeTimer { static int i = 0; static System.Threading.Timer timer; static bool flag = true; static object mylock = new object(); static void Excute(object obj) { Thread.CurrentThread.IsBackground = false; lock (mylock) { if (!flag) { return; } i++; if (i == 80) { timer.Dispose(); flag = false; } Console.WriteLine("Now:" + i.ToString()); } Thread.Sleep(1000);//模拟花时间的代码 } public static void Init() { timer = new System.Threading.Timer(Excute, null, 0, 10); } } class Program { static void test1() { ThreadPool.SetMinThreads(500, 10); Console.Write("是否使用安全方法(Y/N)?"); string key = Console.ReadLine(); if (key.ToLower() == "y") SafeTimer.Init(); else { Console.Write("请输入Timmer响应事件的等待时间(毫秒):");//这个时间直接决定了前80个任务的执行时间,因为等待时间越短,每个任务就可以越快执行完,那么80个任务中就有越多的任务可以用到前面任务执行完后释放掉的线程,也就有越多的任务不必去线程池申请新的线程避免多等待半秒钟的申请时间 string sleep = Console.ReadLine(); Console.Write("申请了80个线程后Timer剩余激发的线程请求是否需要等待时间(Y/N)?");//这里可以发现选Y或者N只要等待时间不变,最终Timer激发线程的次数都相近,说明Timer的确在执行80次的Dispose后就不再激发新的线程了 key = Console.ReadLine(); bool flag = false; if (key.ToLower() == "y") { flag = true; } UnSafeTimer.sw.Start(); UnSafeTimer.Init(Convert.ToInt32(sleep), flag); } Console.WriteLine("Press any key to exit."); Console.ReadLine(); } static int onTimerCount = 0; //static object locker = new object(); static void test2() { onTimerCount = 0; ThreadPool.SetMinThreads(1, 10); ThreadPool.SetMaxThreads(5, 10); System.Timers.Timer t = new System.Timers.Timer(); t.Interval = 500; t.AutoReset = true; t.Elapsed += OnTimedEvent; Console.WriteLine("[{2}] test2() current thread id = {0}/{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, AppDomain.GetCurrentThreadId(), DateTime.Now.ToString("HH:mm:ss.fff")); t.Start(); Thread.Sleep(5000); t.Stop(); Console.WriteLine("Press any key to exit."); Console.ReadLine(); } private static void OnTimedEvent(object sender, System.Timers.ElapsedEventArgs e) { DateTime dt = DateTime.Now; ++onTimerCount; int tmpcount = onTimerCount; Console.WriteLine("[{3}] OnTimedEvent({2}) BEGIN: current thread id = {0}/{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, AppDomain.GetCurrentThreadId(), tmpcount, dt.ToString("HH:mm:ss.fff")); Thread.Sleep(3100); Console.WriteLine("[{3}] OnTimedEvent({2}) END: current thread id = {0}/{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, AppDomain.GetCurrentThreadId(), tmpcount, DateTime.Now.ToString("HH:mm:ss.fff")); } static void test3() { onTimerCount = 0; ThreadPool.SetMinThreads(1, 10); ThreadPool.SetMaxThreads(5, 10); System.Threading.Timer t = new System.Threading.Timer(TimedCB); Console.WriteLine("[{2}] test3() current thread id = {0}/{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, AppDomain.GetCurrentThreadId(), DateTime.Now.ToString("HH:mm:ss.fff")); t.Change(0, 500); //System.Threading.Timer t = new System.Threading.Timer(TimedCB, null, 0, 500); Thread.Sleep(5000); t.Change(-1, Timeout.Infinite); Console.WriteLine("Press any key to exit."); Console.ReadLine(); } private static void TimedCB(object state) { DateTime dt = DateTime.Now; ++onTimerCount; int tmpcount = onTimerCount; Console.WriteLine("[{3}] TimedCB({2}) BEGIN: current thread id = {0}/{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, AppDomain.GetCurrentThreadId(), tmpcount, dt.ToString("HH:mm:ss.fff")); Thread.Sleep(3100); Console.WriteLine("[{3}] TimedCB({2}) END: current thread id = {0}/{1}", System.Threading.Thread.CurrentThread.ManagedThreadId, AppDomain.GetCurrentThreadId(), tmpcount, DateTime.Now.ToString("HH:mm:ss.fff")); } static void Main(string[] args) { //test1(); test2(); test3(); } } }
运行结果:
[21:15:06.807] test2() current thread id = 1/15444 [21:15:07.328] OnTimedEvent(1) BEGIN: current thread id = 4/27956 [21:15:07.827] OnTimedEvent(2) BEGIN: current thread id = 5/2664 [21:15:08.341] OnTimedEvent(3) BEGIN: current thread id = 6/29164 [21:15:08.853] OnTimedEvent(4) BEGIN: current thread id = 7/12292 [21:15:09.365] OnTimedEvent(5) BEGIN: current thread id = 8/28156 [21:15:10.443] OnTimedEvent(1) END: current thread id = 4/27956 [21:15:10.938] OnTimedEvent(2) END: current thread id = 5/2664 [21:15:10.938] OnTimedEvent(6) BEGIN: current thread id = 5/2664 [21:15:11.446] OnTimedEvent(3) END: current thread id = 6/29164 [21:15:11.446] OnTimedEvent(7) BEGIN: current thread id = 6/29164 Press any key to exit. [21:15:11.959] OnTimedEvent(4) END: current thread id = 7/12292 [21:15:12.472] OnTimedEvent(5) END: current thread id = 8/28156 [21:15:14.054] OnTimedEvent(6) END: current thread id = 5/2664 [21:15:14.548] OnTimedEvent(7) END: current thread id = 6/29164 [21:15:20.428] test3() current thread id = 1/15444 [21:15:20.429] TimedCB(1) BEGIN: current thread id = 5/2664 [21:15:20.932] TimedCB(2) BEGIN: current thread id = 6/29164 [21:15:21.442] TimedCB(3) BEGIN: current thread id = 7/12292 [21:15:21.952] TimedCB(4) BEGIN: current thread id = 8/28156 [21:15:22.965] TimedCB(5) BEGIN: current thread id = 4/27956 [21:15:23.536] TimedCB(1) END: current thread id = 5/2664 [21:15:23.536] TimedCB(6) BEGIN: current thread id = 5/2664 [21:15:24.034] TimedCB(2) END: current thread id = 6/29164 [21:15:24.050] TimedCB(7) BEGIN: current thread id = 6/29164 [21:15:24.557] TimedCB(3) END: current thread id = 7/12292 [21:15:24.557] TimedCB(8) BEGIN: current thread id = 7/12292 [21:15:25.054] TimedCB(4) END: current thread id = 8/28156 [21:15:25.069] TimedCB(9) BEGIN: current thread id = 8/28156 Press any key to exit. [21:15:26.069] TimedCB(5) END: current thread id = 4/27956 [21:15:26.641] TimedCB(6) END: current thread id = 5/2664 [21:15:27.156] TimedCB(7) END: current thread id = 6/29164 [21:15:27.667] TimedCB(8) END: current thread id = 7/12292 [21:15:28.178] TimedCB(9) END: current thread id = 8/28156