我一直在阅读Daniel Solis的Illustrated C# 2008(一本优秀的书,顺便说一句),并决定花更多时间在活动上来进一步理解这个话题。我试图理解为什么每次运行该程序时都会看到不同的结果,以及我可以从中学到什么。这些Timer事件为什么会在不一致的时候产生?
(源代码如下)在书中的示例代码中,有一个MyTimerClass
,它有一个订阅System.Timers.Timer
的事件。还有两个其他类,ClassA和ClassB,它们都具有写入控制台的事件处理程序(一个是静态的,另一个不是)。在程序的main
函数中,这些类的事件处理程序绑定到MyTimerClass
的实例中的事件。另一个函数通过lambda表达式添加到事件成员中。
使用作者的代码后,我决定添加另一个类,ClassC
。我不是在程序的Main
函数中添加事件处理程序,而是决定在ClassC
的构造函数中创建一个单独的MyTimerClass
对象,然后订阅MyTimerClass
的事件。
当我在3个不同的场合运行我的代码4.25秒时,我的结果总是以不同的顺序。订单的Main
函数的事件总是以相同的顺序调用ClassA
,ClassB
,然后是Lambda。但是,ClassC
的其他事件似乎总是以完全随机的顺序调用。我还注意到,第一组方法调用似乎有稍微不同的时间,而后面的组都有相同的时间。这是为什么?
(1) Event 1 - ClassA - 51:259
Event 2 - ClassC - 51:259
(2) Event 1 - ClassB - 51:261
(3) Event 1 - Lambda - 51:262
(1) Event 1 - ClassA - 52:271
(2) Event 1 - ClassB - 52:271
(3) Event 1 - Lambda - 52:271
Event 2 - ClassC - 52:271
(1) Event 1 - ClassA - 53:285
(2) Event 1 - ClassB - 53:285
(3) Event 1 - Lambda - 53:285
Event 2 - ClassC - 53:285
(1) Event 1 - ClassA - 54:299
(2) Event 1 - ClassB - 54:299
(3) Event 1 - Lambda - 54:299
Event 2 - ClassC - 54:299
(1) Event 1 - ClassA - 17:30
Event 2 - ClassC - 17:30
(2) Event 1 - ClassB - 17:32
(3) Event 1 - Lambda - 17:33
(1) Event 1 - ClassA - 18:42
(2) Event 1 - ClassB - 18:42
(3) Event 1 - Lambda - 18:42
Event 2 - ClassC - 18:42
(1) Event 1 - ClassA - 19:56
(2) Event 1 - ClassB - 19:56
(3) Event 1 - Lambda - 19:56
Event 2 - ClassC - 19:56
Event 2 - ClassC - 20:70
(1) Event 1 - ClassA - 20:70
(2) Event 1 - ClassB - 20:70
(3) Event 1 - Lambda - 20:70
(1) Event 1 - ClassA - 45:220
Event 2 - ClassC - 45:221
(2) Event 1 - ClassB - 45:223
(3) Event 1 - Lambda - 45:223
(1) Event 1 - ClassA - 46:232
(2) Event 1 - ClassB - 46:232
(3) Event 1 - Lambda - 46:232
Event 2 - ClassC - 46:232
Event 2 - ClassC - 47:246
(1) Event 1 - ClassA - 47:246
(2) Event 1 - ClassB - 47:246
(3) Event 1 - Lambda - 47:246
(1) Event 1 - ClassA - 48:260
(2) Event 1 - ClassB - 48:260
(3) Event 1 - Lambda - 48:260
Event 2 - ClassC - 48:260
这里的源代码,我的控制台应用程序:
class Program
{
static void Main(string[] args)
{
MyTimerClass mc = new MyTimerClass();
ClassA ca = new ClassA();
ClassC cc = new ClassC();
mc.MyElapsed += ca.TimerHandlerA;
mc.MyElapsed += ClassB.TimerHandlerB;
mc.MyElapsed += (obj, e) =>
{
Console.WriteLine("(3) Event 1 - Lambda - {0}:{1}",
System.DateTime.Now.Second,
System.DateTime.Now.Millisecond);
};
Thread.Sleep(4250);
}
}
class ClassA
{
public void TimerHandlerA(Object obj, EventArgs e)
{
Console.WriteLine("(1) Event 1 - ClassA - {0}:{1}",
System.DateTime.Now.Second,
System.DateTime.Now.Millisecond);
}
}
class ClassB
{
public static void TimerHandlerB(Object obj, EventArgs e)
{
Console.WriteLine("(2) Event 1 - ClassB - {0}:{1}",
System.DateTime.Now.Second,
System.DateTime.Now.Millisecond);
}
}
class ClassC
{
public void TimerHandlerC(Object obj, EventArgs e)
{
Console.WriteLine(" Event 2 - ClassC - {0}:{1}",
System.DateTime.Now.Second,
System.DateTime.Now.Millisecond);
}
public ClassC()
{
// This will create a separate MyTimerClass and
// attach ClassC's event handler to mc's event.
MyTimerClass mc = new MyTimerClass();
mc.MyElapsed += TimerHandlerC;
}
}
public class MyTimerClass
{
public event EventHandler MyElapsed;
private void OnOneSecond(Object obj, EventArgs e)
{
if (MyElapsed != null)
MyElapsed(obj, e);
}
private System.Timers.Timer MyPrivateTimer;
public MyTimerClass()
{
MyPrivateTimer = new System.Timers.Timer();
// This will attach the OnOneSecond Event Handler
// to the system timer which will then raise
// MyElapsed.
MyPrivateTimer.Elapsed += OnOneSecond;
// This sets the interval at 1 second.
MyPrivateTimer.Interval = 1000;
// This turns the timer on when the the class
// is instantiated.
MyPrivateTimer.Enabled = true;
}
}
三个问题:
- 为什么,结果每次都是不同的,是什么原因导致这样的事情发生?
- 为什么第一个结果块的时间稍微偏离,而后续块的时间相同?
- 我应该从这个例子中学到什么?
的QPC方法通过秒表类暴露在.NET。但最终,Windows不是为用户应用程序设计的“实时”操作系统;准确的亚毫秒时间是很难做到的。 – 2009-11-10 04:58:14
感谢StopWatch笔记,以及关于Windows的优秀点。我相应地更新了我的答案。 – 2009-11-10 05:10:10
谢谢你的解释。我并不担心时间,因为我是关于什么导致事件以不同的顺序开火。我从罗素的解释抢走了最好的事情是让我的代码是在保证我希望为了执行注册一个事件处理程序。 – 2009-11-10 05:48:11