C#中的三种timer
转
https://blog.csdn.net/hoiven/article/details/51362582
如果你需要使用规律的时间间隔重复执行一些方法,最简单的方式是使用定时器(timer)。
.NET Framework 提供了 4 种定时器。下边两个类是通用的多线程定时器:
(1)System.Threading.Timer
(2)System.Timers.Timer
另外两个是专用的单线程定时器:
(3)System.Windows.Forms.Timer (Windows Forms 的定时器)
(4)System.Windows.Threading.DispatcherTimer (WPF 的定时器)
多线程定时器更加强大、精确并且更加灵活,而单线程定时器对于一些简单的更新 Windows Forms 和 WPF 控件的任务来说是安全的,并且更加便捷。
1.多线程定时器
System.Threading.Timer是最简单的多线程定时器:它仅仅有一个构造方法和两个普通方法(取悦于极简主义者,还有本书作者!)。在接下来的例子中,一个定时器在 5 秒钟之后调用Tick方法来打印 “ tick… “,之后每秒打印一次直到用户按下回车键:
using System;
using System.Threading; class Program
{
static void Main()
{
// 首次间隔 5000ms,之后间隔 1000ms
Timer tmr = new Timer (Tick, "tick...", , );
Console.ReadLine();
tmr.Dispose(); // 停止定时器并执行清理工作
} static void Tick (object data)
{
// 这里运行在一个线程池线程上
Console.WriteLine (data); // 打印 "tick..."
}
}
之后可以通过调用Change方法来改变定时器的时间间隔。如果你希望定时器只触发一次,可以指定Timeout.Infinite作为构造方法的最后一个参数。
2、.NET Framework 在System.Timers命名空间下提供了另一个名字相同的定时器类。它只是封装了 System.Threading.Timer,并在使用完全相同的底层引擎的前提下提供额外的便利。下面是增加功能的简介:
(1)实现了Component,允许用于 Visual Studio 的设计器中。
(2)Interval属性代替了Change方法。
(3)Elapsed事件代替了回调委托。
(4)Enabled属性用于开始或停止定时器(默认值是false)。
(5)Start和Stop方法,避免对Enabled属性感到困惑。
(6)AutoReset标识来指定是否为可重复的事件(默认为true)。
SynchronizingObject属性提供Invoke和BeginInvoke方法,用于在 WPF 和 Windows Forms 控件上安全调用方法。
using System;
using System.Timers; // 命名空间是 Timers 而不是 Threading class SystemTimer
{
static void Main()
{
Timer tmr = new Timer(); // 无需任何参数
tmr.Interval = ;
tmr.Elapsed += tmr_Elapsed; // 使用事件代替委托
tmr.Start(); // 开启定时器
Console.ReadLine();
tmr.Stop(); // 停止定时器
Console.ReadLine();
tmr.Start(); // 重启定时器
Console.ReadLine();
tmr.Dispose(); // 永久停止定时器
} static void tmr_Elapsed (object sender, EventArgs e)
{
Console.WriteLine ("Tick");
}
}
多线程定时器使用线程池来允许少量线程服务多个定时器。这意味着,回调方法或Elapsed事件每次可能会在不同的线程上触发。此外,不论之前的Elapsed是否完成执行,Elapsed总是几乎按时触发。因此,回调方法或事件处理器必须是线程安全的。
多线程定时器的精度依赖于操作系统,通常是在 10-20 ms 的区间。如果需要更高的精度,你可以使用本地互操作(native interop)来调用 Windows 多媒体定时器,可以让精度提升到 1 ms。它定义在 winmm.dll 中,首先调用timeBeginPeriod来通知操作系统你需要更高的定时器精度,然后调用timeSetEvent来启动多媒体定时器。当使用完成后,调用timeKillEvent停止定时器,最后调用timeEndPeriod通知操作系统你不在需要更高的定时器精度了。可以通过搜索关键字 dllimport winmm.dll timesetevent 在网上找到完整的例子。
3、它们暴露的成员都像System.Timers.Timer一样(Interval、Tick、Start和Stop),并且用法也类似。但是不同之处在于其内部是如何工作的。它们不是使用线程池来产生定时器事件,WPF 和 Windows Forms 定时器依赖于 UI 模型的底层消息循环机制(message pumping mechanism)。意味着Tick事件总是在创建该定时器的那个线程触发,在通常的程序中,它也就是管理所有 UI 元素和控件的那个线程。
单线程计时器比较安全,对于更新 Windows Forms controls或者WPF这种简单任务来说更方便。在WPF或Windows Forms中安全的调用方法的SynchronizingObject对象。
单线程计时器是被设计成属于他们执行环境的计时器,如果你在一个Windows服务应用程序中使用Windows Forms的Timer,timer 事件并不会被触发,只有在对应的环境下才会被触发。
像System.Timers.Timer一样,他们也提供了相同的成员(Interval,Tick,Start,Stop),但是他们内部的工作原理不同,WPF和Windows Forms的计时器使用消息循环机制来取代线程池产生消息的机制。
你可以不必考虑线程安全。
新的Tick在之前的Tick完成执行前不会触发。
你可以直接在Tick时间事件的处理代码中更新 UI 控件,而不需要调用Control.Invoke或Dispatcher.Invoke。
这听起来好的难以置信,直到你意识到使用这些定时器的程序并不是真正的多线程,不会有并行执行。一个线程服务于所有定时器,并且还处理 UI 事件。这带来了单线程定时器的缺点:
除非Tick事件处理器执行的很快,否则 UI 会失去响应。
这使得 WPF 和 Windows Forms 定时器仅适用于小任务,通常就是那些更新 UI 外观的任务(例如,显示时钟或倒计时)。否则,你就需要多线程定时器。
在精度方面,单线程定时器与多线程定时器类似(几十毫秒),但是通常精度更低,因为它们会被其它 UI 请求(或其它定时器事件)推迟。
单线程计时器基于Windows消息循环,应用程序会同步的处理计时器的消息。会发现UI界面相应速度比较慢。解决这个问题的方法是使用多线程计时器。
单线程计时器的缺点:除非Tick事件的处理代码执行的非常快,否则UI界面会变得响应很慢。所以 WPF和Windows Forms的计时器都非常适合小任务,尤其是界面更新的任务。例如时钟和计数显示。否则,你需要一个多线程计时器
用法举例
System.Timers.Timer是多线程定时器,如果一个Timer没有处理完成,到达下一个时间点,新的Timer同样会被启动,所以在使用Timer时需要注意,当设定的时间间隔远大于任务时间时,能够实现只在一个线程中执行,但是不能确保一定是一个。
https://blog.csdn.net/yl2isoft/article/details/51346469
如何prevent System.Timers.Timer的触发事件从一个线程池排队来执行?(How to prevent System.Timers.Timer from queuing for execution on a thread pool?)
There is a problem with standard System.Timers.Timer behaviour. The timer raise Elapsed event with some interval. But when time of execution inside Elapsed event handler exceed timer interval then thread pool begin queuing event handling. This is a problem in my case. This is because with my Elapsed event handler I fetch some data from database and doing something with it and finally save results back to database. But data handling should be provided only once. So, is there a way to prevent from queuing elapse events for System.Timers.Timer.(怎样只让事件执行一次)
As illustration for this issue you can consider next test program:
public class EntryPoint
{ private static void TimeProc(object state, ElapsedEventArgs e)
{
Console.WriteLine("Current time {0} on the thread {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep();
} static void Main(string[] args)
{
Console.WriteLine("Press <Enter> for finishing\n\n");
ThreadPool.SetMaxThreads(, );
System.Timers.Timer MyTimer = new System.Timers.Timer();
MyTimer.Elapsed += new ElapsedEventHandler(TimeProc);
MyTimer.Start();
Console.ReadLine();
MyTimer.Stop();
}
}
解决方法:
public class EntryPoint
{
private static System.Timers.Timer MyTimer;
private static void TimeProc(object state, ElapsedEventArgs e)
{
Console.WriteLine("Current time {0} on the thread {1}", DateTime.Now, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep();
MyTimer.Enabled = true;
} static void Main(string[] args)
{
Console.WriteLine("Press <Enter> for finishing\n\n");
ThreadPool.SetMaxThreads(, );
MyTimer = new System.Timers.Timer();
MyTimer.AutoReset = false; MyTimer.Elapsed += new ElapsedEventHandler(TimeProc);
MyTimer.Enabled = true;
Console.ReadLine(); }
}
以上方法似乎不行,不知道有什么能够确保只在一个线程中执行触发函数的方法。
https://www.cnblogs.com/dotnet261010/p/7113523.html
https://www.cnblogs.com/yang-fei/p/6169089.html
C#中的三种timer的更多相关文章
- .NET中的三种Timer的区别和用法
最近正好做一个WEB中定期执行的程序,而.NET中有3个不同的定时器.所以正好研究研究.这3个定时器分别是: //1.实现按用户定义的时间间隔引发事件的计时器.此计时器最宜用于 Windows 窗体应 ...
- .NET中的三种Timer的区别和用法(转)
最近正好做一个WEB中定期执行的程序,而.NET中有3个不同的定时器.所以正好研究研究.这3个定时器分别是: //1.实现按用户定义的时间间隔引发事件的计时器.此计时器最宜用于 Windows 窗 ...
- 转:.NET中的三种Timer的区别和用法(转)
//1.实现按用户定义的时间间隔引发事件的计时器.此计时器最宜用于 Windows 窗体应用程序中,并且必须在窗口中使用. System.Windows.Forms.Timer // 2.提供以指定的 ...
- 【转】.NET中的三种Timer的区别和用法
最近正好做一个WEB中定期执行的程序,而.NET中有3个不同的定时器.所以正好研究研究.这3个定时器分别是: //1.实现按用户定义的时间间隔引发事件的计时器.此计时器最宜用于 Windows 窗体应 ...
- .NET中的三种Timer的区别和用法(收集)
最近正好做一个WEB中定期执行的程序,而.NET中有3个不同的定时器.所以正好研究研究.这3个定时器分别是: 1.实现按用户定义的时间间隔引发事件的计时器.此计时器最宜用于 Windows 窗体应用程 ...
- Java三大框架之——Hibernate中的三种数据持久状态和缓存机制
Hibernate中的三种状态 瞬时状态:刚创建的对象还没有被Session持久化.缓存中不存在这个对象的数据并且数据库中没有这个对象对应的数据为瞬时状态这个时候是没有OID. 持久状态:对象经过 ...
- Asp.Net中的三种分页方式
Asp.Net中的三种分页方式 通常分页有3种方法,分别是asp.net自带的数据显示空间如GridView等自带的分页,第三方分页控件如aspnetpager,存储过程分页等. 第一种:使用Grid ...
- httpClient中的三种超时设置小结
httpClient中的三种超时设置小结 本文章给大家介绍一下关于Java中httpClient中的三种超时设置小结,希望此教程能给各位朋友带来帮助. ConnectTimeoutExceptio ...
- MySQL buffer pool中的三种链
三种page.三种list.LRU控制调优 一.innodb buffer pool中的三种页 1.free page:从未用过的页 2.clean page:干净的页,数据页的数据和磁盘一致 3.d ...
随机推荐
- 【树】Populating Next Right Pointers in Each Node
题目: Given a binary tree struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode ...
- 常用CSS实例
为表格设置合并边框模型: border-collapse:collapse 规定单元格之间的空间: cellspacing:0 规定内侧边框的哪个部分是可见的: rules:all
- tensorflow model save and restore
TensorFlow 模型保存/载入 我们在上线使用一个算法模型的时候,首先必须将已经训练好的模型保存下来.tensorflow保存模型的方式与sklearn不太一样,sklearn很直接,一个skl ...
- 机器学习--降维算法:PCA主成分分析
引言 当面对的数据被抽象为一组向量,那么有必要研究一些向量的数学性质.而这些数学性质将成为PCA的理论基础. 理论描述 向量运算即:内积.首先,定义两个维数相同的向量的内积为: (a1,a2,⋯,an ...
- Hadoop网站日志数据清洗——正则表达式实现
周旭龙前辈的Hadoop学习笔记—网站日志分析项目案例简明.经典,业已成为高校大数据相关专业的实验项目.上周博主也完成了这个实验,不同于周前辈使用特殊符号切割字符串得到数据的做法,博主使用了正则表达式 ...
- Java 集合框架(三)—— LinkedList
三.链表 —— LinkedList ArrayList 虽然好用,但是数组和数组列表都有一个重大的缺陷:从数组的中间位置删除一个元素要付出很大的代价,其原因是数组中处于被删除元素之后的所有元素都要向 ...
- java 基本理论知识点
通过JAVAOO 的笔试后,总结了一些理论的知识点. 1.main方法是怎么写的 public static void main(String [] args){}//最习惯的 public stat ...
- 亿级别记录的mongodb批量导入Es的java代码完整实现
针对mongodb亿级别或者十亿级别的模糊查询,效率不高,解决方式是使用Es查询,这样就需要把数据导入的ES中 完整的代码实现如下所示:(仅供参考) import java.io.IOExceptio ...
- hadoop学习笔记(六):HDFS文件的读写流程
一.HDFS读取文件流程: 详解读取流程: Client调用FileSystem.open()方法: 1 FileSystem通过RPC与NN通信,NN返回该文件的部分或全部block列表(含有blo ...
- c#基础学习(0702)之面向对象和方法重写概述
面向对象编程(OOP==>Object-Oriented Programming) OOA:面向对象分析 OOD:面向对象设计 OOAD:面向对象分析与设计 什么是面向对象?一种分析问题的方式( ...