您的位置:首页 > 编程语言 > C#

c# - Timer中的一个问题

2017-08-17 14:27 363 查看
我们知道,System.Threading.Timer可以定时每隔一段时间执行一次任务。

不知道大家有没有想过,如果任务执行时间比较长,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);
}
}
}
}


以上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐