C#执行定时计算限制操作(计时器)

2024-04-08 08:58

本文主要是介绍C#执行定时计算限制操作(计时器),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

c#执行定时计算限制操作(计时器)

在.Net Framework Class Library(FCL)中,System.Threading命名空间下定义了一个Timer类,这就是常用的一个计时器。实际上FCL总共提供了如下几种计时器:

1、System.Threading.Timer

在实际的开发中,这个类出现和使用频率非常高,下面就重点谈谈它的一些基础概念和应用实例。

(1)、常用的构造器

1
2
3
4
public  Timer(TimerCallback callback, object  state, int  dueTime, int  period);
public  Timer(TimerCallback callback, object  state, long  dueTime, long  period);
public  Timer(TimerCallback callback, object  state, TimeSpan dueTime, TimeSpan period);
public  Timer(TimerCallback callback, object  state, uint  dueTime, uint  period);

参数说明:

a、callback:望文生意,肯定表示一个回调,它是标识希望由一个线程池线程回调的方法。当然它的类型必须和System.Threading.TimerCallback委托类型匹配,如下所示:

1
public  delegate  void  TimerCallback( object  state);

b、state:每次调用回调方法,向回调方法传递的状态数据,如没有,可以为null;

c、dueTime:在首次调用回调方法之前要等待多少毫秒。如希望立刻调用回调方法,该参数指定为0即可。

d、period:指定了以后每次调用回调方法之前要等待多少毫秒(理解成下一次和本次调用的时间间隔即可)。如果为该参数传递Timeout.Infinite(或者直接写-1),线程池线程只调用回调方法一次(那也就没有必要用计时器了)。

 

(2)、基本工作原理

在内部(原文应该指CLR内),线程池为所有Timer对象只使用了一个线程。这个线程知道下一个Timer对象在什么时候到期(计时器还有多久触发)。下一个Timer对象到期时,线程就会唤醒,在内部调用ThreadPool的QueueUserWorkItem,将一个工作项添加到线程池的队列中,使你的回调方法得到调用。

注意:如果回调方法的执行时间很长,计时器可能在上个回调还没有完成的时候再次触发(对于执行时间很长的任务,实际开发中通常不使用线程池,而是直接使用new一个Thread)。这可能会造成多个线程池线程同时调用你的方法(方法的重叠覆盖?)。为了解决这个问题,Jeffrey Richter建议我们这样使用Timer:

a、为period指定Timeout.Infinite。这样,计时器就只触发一次;

b、在回调方法中,调用Timer的Change方法来指定一个新的dueTime,并再次为period指定Timeout.Infinite。Change方法的几个重载版本:

1
2
3
4
5
6
7
public  bool  Change( int  dueTime, int  period);
public  bool  Change( long  dueTime, long  period);
public  bool  Change(TimeSpan dueTime, TimeSpan period);
public  bool  Change( uint  dueTime, uint  period);

Timer还有一个Dispose方法,允许完全取消计时器。

(3)、示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
internal  static  class  TimerDemo
{
     private  static  Timer s_timer;
     public  static  void  Main()
     {
         Console.WriteLine( "Main thread: starting a timer" );
         using  (s_timer = new  Timer(ComputeBoundOp, 5, 0, Timeout.Infinite))
         {
             Console.WriteLine( "Main thread: Doing other work here..." );
             Thread.Sleep(10000);  // Simulating other work (10 seconds)
         } // Calls Dispose to cancel the timer now
         Console.Read();
     }
     // This method's signature must match the TimerCallback delegate
     private  static  void  ComputeBoundOp(Object state)
     {
         // This method is executed by a thread pool thread
         Console.WriteLine( "In ComputeBoundOp: state={0}" , state);
         Thread.Sleep(1000);  // Simulates other work (1 second)
         // Have the Timer call this method again in 2 seconds
         s_timer.Change(2000, Timeout.Infinite);
         // When this method returns, the thread goes back
         // to the pool and waits for another work item
     }
}

这个示例是<<CLR via C#>>中的源码,虽然简单,却贯穿实现了创建Timer,Timer定时工作到Timer的销毁一整个生命周期。using语句我们可以使用try finally替换,在finally语句块中显式调用Dispose方法。注意,程序中输出了四次“In ComputeBoundOp: state=5”,您不妨多想一想为什么只有4次。而如果我们把Main方法的这一行:

1
Thread.Sleep(10000);  // Simulating other work (10 seconds)

注释掉,程序有时候会抛出“程序无法访问已释放对象”的异常,而且每次输出的结果可能还不一样。之所以这么说,是因为using语句不能保证静态Timer立刻被垃圾回收器回收。您不妨自己动手一试。

 

2、System.Timers.Timer

这个类据说基本上就是System.Threading.Timer的包装过的“整过容的副产品”。当计时器到期触发时,会导致CLR将事件放到线程池的队列中。该类派生自System.ComponentModel的Component类,允许VS将计时器对象放到设计平面上,并公开了它的属性和事件(不就是一个控件吗,难道?)。

 

3、System.Windows.Forms.Timer

构造一个该类的实例,相当于告诉Windows将一个计时器和调用线程关联。当这个计时器被触发时,Windows将一条及时消息注入线程的消息队列。线程必须执行一个消息泵来提取这些消息,并把它们派遣给想要的回调方法。注意,所有这些工作都只由一个线程完成——设置计时器的线程保证就是执行回调方法的线程。这还意味着你的计时器方法不会由多个线程并发执行。

 

4、System.Windows.Threading.DispatcherTimer

这个类是System.Windows.Forms的Timer在WPF和SilverLight应用程序中的等价物。通俗地说,这个类也就是System.Windows.Forms的Timer在WPF和SilverLight下的一个马甲。擅于改头换面新瓶装旧酒在MS的技术领域中也不是一天两天的事情了。

 

在Jeffrey Richter 的<<CLR via C#>>中关于计时器有很精练的说明,其中他说“事实上,我个人从来不用System.Timers.Timer类,建议你也不要用它”,他的这种态度蛮好玩的。反正对于这个类我倒是用过不少,而且一直没出过什么差错,就算是”山寨“或者”马甲“也不是从来都是一无是处。

 

参考:

Jeffrey Richter <<CLR via C#>>

http://msdn.microsoft.com/zh-cn/library/system.threading.timer.aspx

原文地址:

http://www.cnblogs.com/jeffwongishandsome/archive/2010/11/15/1877837.html

这篇关于C#执行定时计算限制操作(计时器)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/885131

相关文章

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

Oracle数据库定时备份脚本方式(Linux)

《Oracle数据库定时备份脚本方式(Linux)》文章介绍Oracle数据库自动备份方案,包含主机备份传输与备机解压导入流程,强调需提前全量删除原库数据避免报错,并需配置无密传输、定时任务及验证脚本... 目录说明主机脚本备机上自动导库脚本整个自动备份oracle数据库的过程(建议全程用root用户)总结

Python操作PDF文档的主流库使用指南

《Python操作PDF文档的主流库使用指南》PDF因其跨平台、格式固定的特性成为文档交换的标准,然而,由于其复杂的内部结构,程序化操作PDF一直是个挑战,本文主要为大家整理了Python操作PD... 目录一、 基础操作1.PyPDF2 (及其继任者 pypdf)2.PyMuPDF / fitz3.Fre

解密SQL查询语句执行的过程

《解密SQL查询语句执行的过程》文章讲解了SQL语句的执行流程,涵盖解析、优化、执行三个核心阶段,并介绍执行计划查看方法EXPLAIN,同时提出性能优化技巧如合理使用索引、避免SELECT*、JOIN... 目录1. SQL语句的基本结构2. SQL语句的执行过程3. SQL语句的执行计划4. 常见的性能优

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

C#中lock关键字的使用小结

《C#中lock关键字的使用小结》在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时,其他线程无法访问同一实例的该代码块,下面就来介绍一下lock关键字的使用... 目录使用方式工作原理注意事项示例代码为什么不能lock值类型在C#中,lock关键字用于确保当一个线程位于给定实例的代码块中时

MySQL 强制使用特定索引的操作

《MySQL强制使用特定索引的操作》MySQL可通过FORCEINDEX、USEINDEX等语法强制查询使用特定索引,但优化器可能不采纳,需结合EXPLAIN分析执行计划,避免性能下降,注意版本差异... 目录1. 使用FORCE INDEX语法2. 使用USE INDEX语法3. 使用IGNORE IND

C# $字符串插值的使用

《C#$字符串插值的使用》本文介绍了C#中的字符串插值功能,详细介绍了使用$符号的实现方式,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录$ 字符使用方式创建内插字符串包含不同的数据类型控制内插表达式的格式控制内插表达式的对齐方式内插表达式中使用转义序列内插表达式中使用

C#中的Converter的具体应用

《C#中的Converter的具体应用》C#中的Converter提供了一种灵活的类型转换机制,本文详细介绍了Converter的基本概念、使用场景,具有一定的参考价值,感兴趣的可以了解一下... 目录Converter的基本概念1. Converter委托2. 使用场景布尔型转换示例示例1:简单的字符串到

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到