C#三种定时器
三个定时器分别是
- 实现按用户定义的时间间隔引发事件的计时器。此计时器最宜用于 Windows 窗体应用程序中,并且必须在窗口中使用。
System.Windows.Forms.Timer - 提供以指定的时间间隔执行方法的机制。无法继承此类。
System.Threading.Timer - 在应用程序中生成定期事件。
System.Timers.Timer
Forms.Timer
这个timer跟js中的定时器道理相同,它并不开辟一个线程,它只是把事件加入到队列中,它用的是UI线程。所以它的好处就是轻便简单。因为没有实体不消耗资源,所以这个timer无法回收。窗体timer和线程timer、计时器timer不同,因为后两者dispose之后,GC可以收集,而前者无法收集。
使用这个Forms.Timer不能执行IO,网络请求等耗时操作,否则阻碍UI线程,界面卡住不动。
Timers.Timer和Threading.Timer都会开辟线程。
Timers.Timer
System.Timers.Timer只要处于活动状态,就会一直存在下去,直到你手工停止或宿主线程结束。MSDN上还有这样一段话“Elapsed 事件在 ThreadPool 线程上引发。如果 Elapsed 事件的处理时间比 Interval 长,在另一个 ThreadPool 线程上将会再次引发此事件。因此,事件处理程序应当是可重入的。”也就是说,在你在每次的Elapsed 事件处理在下一次轮循时间到来的时候还没有结束,Timer对象仍然会另一个线程中启动Elapsed 的处理事件。这种机制的后果就可能会导致你的Timer已经被结束了,但是还会再执行Elapsed事件,MSDN的原文:“在一个线程调用 Stop 方法或将Enabled 属性设置为 false 的同时,可在另一个线程上运行事件处理方法。这可能导致在计时器停止之后引发 Elapsed 事件。”针对这种情况,如果你不愿让它发生,你可能就必须做一些额外的工作来避免它的发生。这种机制同样也适用于System.Threading.Timer。
Threading.Timer
System.Threading.Timer : MarshalByRefObject, IDisposable 这是一种轻量经的计时数,它在使用上与System.Timers.Timer的不同表现在:使用回调机制,而不是事件机制。构造器中可以指定首次执行时间(构建后或修改后开始算)和间隔执行时间,这两个时间(dueTime,period)可以是不同的。它是没有开始和结束控制接口,从构建开始算,直至释放结束。它基于ThreadPool线程机制,遵循着上述System.Timers.Timer的相同原则(红色部分)。同时它在生命周期方面也有必须要注意的地方,它没有开始或停止(有释放接口Dispose)方法。在它的生命周期中,必须被其它对象所引用。一旦它不被任何对象所引用,那么就意味着这个Timer对象变成一个不可达对象,会被GC回收。MSDN原文解释:
“只要在使用 Timer,就必须保留对它的引用。对于任何托管对象,如果没有对 Timer 的引用,计时器会被垃圾回收。即使 Timer 仍处在活动状态,也会被回收。”
如何选择三种计时器
MSDN中还有这样一段话:“System.Threading..::.Timer is a simple, lightweight timer that uses callback methods and is served by thread pool threads. It is not recommended for use with Windows Forms, because its callbacks do not occur on the user interface thread. System.Windows.Forms..::.Timer is a better choice for use with Windows Forms. For server-based timer functionality, you might consider using System.Timers..::.Timer, which raises events and has additional features.”它告诉我们:System.Threading.Timer是一个简单的,轻量级的,利用回调机制和线程池机制的计时器。在Windows Forms的场景下不建议我们使用这个对象,因为UI线程并不触发回调函数,取而代之是Windows.Forms.Timer ,而如果希望利用基于服务器计时器的功能,则建议我们使用System.Timers.Timer。System.Windows.Forms.Timer : System.ComponentModel.Component 这一种专门服务于Windows Forms的计时器,它在机制和原理上都与前面两种有着比较大的区别。在接口使用上与System.Timers.Timer比较相似,同时具备了一些的Windows Form控件的特征。同时它的精度设计上也不是很高。“Timer 用于以用户定义的事件间隔触发事件。Windows 计时器是为单线程环境设计的,其中,UI 线程用于执行处理。它要求用户代码有一个可用的 UI 消息泵,而且总是在同一个线程中操作,或者将调用封送到另一个线程。使用此计时器时,请使用 Tick 事件执行轮询操作,或在指定的时间内显示启动画面。每当Enabled 属性设置为 true 且 Interval 属性大于 0 时,将引发 Tick 事件,引发的时间间隔基于Interval 属性设置。”
非控件的创建线程不能操作控件。否则运行不报错但调试会报错。
关于垃圾回收
MSDN的描述: 只要在使用 Timer,就必须保留对它的引用。对于任何托管对象,如果没有对 Timer 的引用,计时器会被垃圾回收。即使 Timer 仍处在活动状态,也会被回收。当不再需要计时器时,请使用 Dispose 方法释放计时器持有的资源。如果希望在计时器被释放时接收到信号,请使用接受 WaitHandle 的 Dispose(WaitHandle) 方法重载。计时器已被释放后,WaitHandle 便终止。
而我说:如果一个对象的成员函数正在被执行,那么这个对象肯定不会被收集
要想对无引用的对象进行收集,就必须要终止这个对象的一切timer成员,否则无法收集该对象(因为timer正在使用该对象)。如果不停止timer就直接更改指针(这个对象彻底无法访问了),这就是新时代的内存泄露,程序早晚要内存溢出
timer.stop 和timer.dispose 都会使线程终止,从而可以回收垃圾
所以谨慎为好,不要过于依赖编译器,这个问题是个问题,养成好的编程习惯才能避免很多大坑。
using System;
class TimersTimer {
System.Timers.Timer t;
public TimersTimer() {
Console.WriteLine("Timers.Timer is created");
t = new System.Timers.Timer();
t.Interval = 1;
t.Elapsed += tick;
t.Start();
}
void tick(object o, EventArgs e) {
t.Stop();
Console.WriteLine("tick is called");
}
~TimersTimer() {
Console.WriteLine("Timers.Timer is died");
}
}
class FormTimer {
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
public FormTimer() {
Console.WriteLine("Form.Timer is called");
t.Interval = 1;
t.Tick += tick;
t.Start();
}
void tick(object o, EventArgs e) {
Console.WriteLine("tick is called");
t.Dispose();
}
~FormTimer() {
Console.WriteLine("Form.Timer is deleted");
}
}
class ThreadTimer {
System.Threading.Timer t;
public ThreadTimer() {
Console.WriteLine("thread.timer is called");
t = new System.Threading.Timer(new System.Threading.TimerCallback(tick), null, 0, 1);
}
void tick(object o) {
Console.WriteLine("tick is called");
t.Dispose();
}
~ThreadTimer() {
Console.WriteLine("thread.timer is died");
}
}
class haha {
static void Main() {
new ThreadTimer();
System.Threading.Thread.Sleep(100);
GC.Collect();
System.Windows.Forms.Application.Run();
}
}
C#三种定时器的更多相关文章
- Objective-C三种定时器CADisplayLink / NSTimer / GCD的使用
OC中的三种定时器:CADisplayLink.NSTimer.GCD 我们先来看看CADiskplayLink, 点进头文件里面看看, 用注释来说明下 @interface CADisplayLin ...
- cocos2dx三种定时器使用
cocos2dx三种定时器的使用以及停止schedule.scheduleUpdate.scheduleOnce 今天白白跟大家分享一下cocos2dx中定时器的用法. 首先,什么是定时 ...
- C#中三种定时器对象的比较 【转】
https://www.cnblogs.com/zxtceq/p/5667281.html C#中三种定时器对象的比较 ·关于C#中timer类 在C#里关于定时器类就有3个1.定义在System.W ...
- C#中三种定时器对象的比较
·关于C#中timer类 在C#里关于定时器类就有3个1.定义在System.Windows.Forms里2.定义在System.Threading.Timer类里3.定义在System.Timers ...
- C#三种定时器的实现
http://www.coridc.com/archives/2253.html c#中提供了三种类型的计时器: 1.基于 Windows 的标准计时器(System.Windows.Forms.Ti ...
- iOS三种定时器的用法NSTimer、CADisplayLink、GCD
一,NSTimer //创建方式1 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector: ...
- NSTimer、CADisplayLink、GCD 三种定时器的用法 —— 昉
在软件开发过程中,我们常常需要在某个时间后执行某个方法,或者是按照某个周期一直执行某个方法.在这个时候,我们就需要用到定时器. 在iOS中有很多方法完成定时器的任务,例如 NSTimer.CADisp ...
- android 三种定时器的写法
//两秒后执行new Handler().postDelayed(new Runnable() { @Override public void run() { --todo }}, 2000); -- ...
- cocos2dx三种定时器的使用以及停止schedule,scheduleUpdate,scheduleOnce。
今天白白跟大家分享一下cocos2dx中定时器的使用方法. 首先,什么是定时器呢?或许你有时候会想让某个函数不断的去执行,或许只是执行一次,获取你想让他每隔几秒执行一次,ok,这些都可以统统交给定时器 ...
随机推荐
- Android图片加载框架最全解析(八),带你全面了解Glide 4的用法
本篇将是我们这个Glide系列的最后一篇文章. 其实在写这个系列第一篇文章的时候,Glide就推出4.0.0的RC版了.那个时候因为我一直研究的都是Glide 3.7.0版本,再加上RC版本还不太稳定 ...
- Spark Streaming的编程模型
Spark Streaming的编程和Spark的编程如出一辙,对于编程的理解也非常类似.对于Spark来说,编程就是对于RDD的操作:而对于Spark Streaming来说,就是对DStream的 ...
- OpenCV学习(19) 细化算法(7)
最后再来看一种通过形态学腐蚀和开操作得到骨架的方法.http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/ 代码非常简单: v ...
- fpga状态机详解
什么是状态机:状态机通过不同的状态迁移来完成特定的逻辑操作 状态机的分类:Moore型状态机和Mealy型状态机 Moore型:状态机的变化只与当前的状态有关 Mealy型:状态机的变化不仅与当前的状 ...
- 【用jQuery来判断浏览器的类型】及【javascript获取用户ip地址】
用jQuery来判断浏览器的类型,主要是使用$.browser这个工具类,使用方法: $.browser.['浏览器关键字'] //谷歌浏览器.360浏览器等其他一些浏览器,没有专门的判断 funct ...
- Escape字符总结
有如下的 escape字符. 对于十进制来说,\后面只涵盖3个字符,比如\1234,是\123和字符4. 但是对于十六进制,后面会涵盖四个字符,比如\x1234,后面的四个字符都在\的涵盖范围内.
- 如何用7-zip创建自解压文件,7Z软件如何使用
1 要创建自解压文件,一般都是双击直接解压到C盘的Program Files文件夹里面,或许还需要在桌面创建一个快捷方式之类的.但是一般的绿色软件除了复制到Program Files还需要运行一下绿化 ...
- qtp:vbs基础教程
◎Vbs脚本编程简明教程之中的一个-为什么要使用Vbs? 在Windows中,学习计算机操作或许非常easy,可是非常多计算机工作是反复性劳动,比如你每周或许须要对一些计算机文件进行复制.粘贴.改名 ...
- python中的lambda知多少!
python允许使用lambda关键字创造匿名函数,匿名函数是因为不需要以标准的方式来声明,比如说,使用def语句.(除非赋值给一个局部变量,这样的对象也不会再任何的名字空间内创建名字)然而,作为函数 ...
- android kernel控制台初始化过程
对于我们的android平台,控制台被定义到了串口1上,因此初始化过程就是把控制台的输出配置到串口1上 对kernel控制台初始化是在挂载文件系统之前,由于没有串口的设备文件,不能通过打开设备文件来访 ...