c# - Timer中的一个问题
2017-08-17 14:27
363 查看
我们知道,System.Threading.Timer可以定时每隔一段时间执行一次任务。
不知道大家有没有想过,如果任务执行时间比较长,Interval到期之后会发生什么;是会结束当前的线程,还是会重新启动一个线程?
下面代码我们模拟一下,任务执行时间5s, Interval=2s的运行情况:
从截图里我们看到,2s 时间间隔到期之后,系统除了原始线程之外,会新创建其它线程(原始线程:11;新线程:12,13)。这是我们期望的吗?恐怕大部分情况下不是。
我们期望的是:即使2s的时间间隔到期,系统需要等待当前任务执行完毕之后,再重新启动一个新的执行周期,期间不必创建新的线程。
---------------------------------------------------------------------------------
我们做的第一个尝试是:为Timer对象设置AutoReset=false,之后在Elapsed方法的最后,重新启动Timer,进入新的执行周期。
AutoReset属性的说明如下:Timer should raise the System.Timers.Timer.Elapsed event only once (false) or repeatedly (true)。默认情况下这个值是true,也就是会不间断的触发Elapsed方法;false的意思是只触发一次Elapsed方法。
完整代码如下:
从截图里我们看到,2s 时间间隔到期之后,系统没有创建新的线程;待当前线程执行完毕之后;又重新开始了新的执行周期,与我们期望的相符。
---------------------------------------------------
但是,这就结束了么? No,这太麻烦了,为此我们创建了一个类:
用起来很方便,不用考虑设置AutoReset,不用重新启动执行周期。你只需要考虑时间间隔,和你需要执行的方法。
调用示例如下:
以上。
不知道大家有没有想过,如果任务执行时间比较长,Interval到期之后会发生什么;是会结束当前的线程,还是会重新启动一个线程?
下面代码我们模拟一下,任务执行时间5s, Interval=2s的运行情况:
using System; using System.Timers; namespace TimerTest2 { class Program { static void Main(string[] args) { Timer t1 = new Timer(); t1.Interval = 2000; t1.Elapsed += ct_Elapsed; t1.Start(); Console.ReadLine(); } static void ct_Elapsed(object sender, ElapsedEventArgs e) { int i = 1; // 执行 500ms * 10 = 5s while (i <= 10) { Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " - Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId + " => " + i++); System.Threading.Thread.Sleep(500); } } } }
从截图里我们看到,2s 时间间隔到期之后,系统除了原始线程之外,会新创建其它线程(原始线程:11;新线程:12,13)。这是我们期望的吗?恐怕大部分情况下不是。
我们期望的是:即使2s的时间间隔到期,系统需要等待当前任务执行完毕之后,再重新启动一个新的执行周期,期间不必创建新的线程。
---------------------------------------------------------------------------------
我们做的第一个尝试是:为Timer对象设置AutoReset=false,之后在Elapsed方法的最后,重新启动Timer,进入新的执行周期。
AutoReset属性的说明如下:Timer should raise the System.Timers.Timer.Elapsed event only once (false) or repeatedly (true)。默认情况下这个值是true,也就是会不间断的触发Elapsed方法;false的意思是只触发一次Elapsed方法。
完整代码如下:
using System; using System.Timers; namespace TimerTest2 { class Program { static Timer t1 = new Timer(); static void Main(string[] args) { t1.Interval = 2000; t1.Elapsed += ct_Elapsed; t1.AutoReset = false; t1.Start(); Console.ReadLine(); } static void ct_Elapsed(object sender, ElapsedEventArgs e) { int i = 1; // 执行 500ms * 10 = 5s while (i <= 10) { Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " - Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId + " => " + i++); System.Threading.Thread.Sleep(500); } t1.Start(); } } }
从截图里我们看到,2s 时间间隔到期之后,系统没有创建新的线程;待当前线程执行完毕之后;又重新开始了新的执行周期,与我们期望的相符。
---------------------------------------------------
但是,这就结束了么? No,这太麻烦了,为此我们创建了一个类:
using System.Timers; namespace TimerTest2 { /// <summary> /// 请参考: https://stackoverflow.com/a/10442117/56778 /// </summary> public class CETimer { public event ElapsedEventHandler Elapsed; private Timer T { get; set; } public CETimer(double interval) { InitializeTimer(interval); } public void InitializeTimer() { InitializeTimer(1000); } public void InitializeTimer(double interval) { this.T = new Timer(); this.T.AutoReset = false; this.T.Enabled = false; this.T.Elapsed += InternalElapsed; this.T.Interval = interval; } public void Close() { this.T.Close(); } public void Start() { this.T.Start(); } public void Stop() { this.T.Stop(); } private void InternalElapsed(object sender, ElapsedEventArgs e) { if (this.Elapsed != null) this.Elapsed(sender, e); this.T.Start(); } } }
用起来很方便,不用考虑设置AutoReset,不用重新启动执行周期。你只需要考虑时间间隔,和你需要执行的方法。
调用示例如下:
using System; using System.Timers; namespace TimerTest2 { class Program { static void Main(string[] args) { CETimer ct = new CETimer(2000); ct.Elapsed += ct_Elapsed; ct.Start(); Console.ReadLine(); } static void ct_Elapsed(object sender, ElapsedEventArgs e) { int i = 1; // 执行 500ms * 10 = 5s while (i <= 10) { Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " - Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId + " => " + i++); System.Threading.Thread.Sleep(500); } } } }
以上。
相关文章推荐
- (.Net,C#)线程Timer的一个小问题
- 常量,字段,构造方法 调试 ms 源代码 一个C#二维码图片识别的Demo 近期ASP.NET问题汇总及对应的解决办法 c# chart控件柱状图,改变柱子宽度 使用C#创建Windows服务 C#服务端判断客户端socket是否已断开的方法 线程 线程池 Task .NET 单元测试的利剑——模拟框架Moq
- C#初学踩坑日记-ListBox和ComboBox数据绑定同一个DataSet的问题
- 刚遇到的一个C#中调用api,回调函数的问题
- C#中Timer使用及解决重入问题
- Delphi6 调用 C# Dll 时一个编译问题
- [C#]参数化查询的一个重要问题
- 最近写一个C#关于U盘的操作,在弹出U盘是遇到了些问题,C#调WINdoWs底层的东西太麻烦了,看样子要看看VC或C了
- 困扰多日的C#调用Haskell问题竟然是Windows的一个坑
- 一个C#输出文本文件的问题
- C# 和Jsonp的一个小demo 用jQuery与JSONP轻松解决跨域访问的问题
- 开发一个小工具重温C#经典问题
- C#中新建一个form实例后调用this.close,都关闭的问题
- 强大的C# Expression在一个函数求导问题中的简单运用
- 关于C#timer 时间精确度的问题
- C#串口编程问题:一个测试数据怎么拆分成2个字符串,做了2次发送?
- C#执行oraclec存储过程获取返回值的一个问题(使用到临时表)
- C#中读写Excel的方法及OleDbConnection的一个SQL问题
- 用C#实现的一个简单任务机,解决了一般任务机无法定时执行任务的问题
- C# 调API的一个弱智问题