« 今天作了什么? | Main | 2003年,回头看看 »

从timer看一眼.net的编译机制

作者:virushuo 发表于 2003-12-26 12:12 最后更新于 2005-10-14 16:10
版权声明:按照by-nc-sa的cc协议可转载,拒绝采用“独家” 授权媒介(含网站和平面媒体)转载、引用、链接,除非获得本人许可。转载时请务必以超链接形式标明文章原始出处和作者信息及本声明。


    因为工作需要,制作了一个定时发送数据的windows service,C#开发。其中碰上了一个很有意思的问题。


 


先看看程序大概的结构:


 


初始化


              private void InitializeComponent()

              {

                     this.timer1 = new Timer();

                     this.timer1.Elapsed += new ElapsedEventHandler(timer1_Tick);

              }

       serviceonStart() 

protected override void OnStart(string[] args)

              {

                     timer1.Interval = 6000;

                     timer1.Start();

                     EventLog.WriteEntry(ServiceName +"Event","timer started 1");

              }

定时器触发

              private void timer1_Tick(Object source, ElapsedEventArgs e)

              {

                     DateTime time = DateTime.Now;

                     TimeSpan dayspan=new  TimeSpan(1,0,0,0);

                     time=time.Subtract(dayspan);

                     DateTime dateTime1=new DateTime(time.Year,time.Month,time.Day,0,0,0);

                     DateTime dateTime2=new DateTime(time.Year,time.Month,time.Day,23,59,59);

                    

                     if (time.Hour==8&&time.Minute==30&&lastupdate.Day!=DateTime.Now.Day)

                     {

                           

try


                           
{


                                  
PSOInterfaceWraper PsoWraper = new PSOInterfaceWraper();


                                  
PSOInterfaceWraper.GeneralLedgerAsyncResult Result;


 


                                  
DateTime StartDate=dateTime1;


                                  
DateTime EndDate=dateTime2;

                                   int amount=LedgerAsyncBLL(StartDate,EndDate);

                                   Result = PsoWraper.GeneralLedgerAsync("00",StartDate,EndDate,this.TranslationCount,amount*100);               

                           

                                   EventLog.WriteEntry(ServiceName +" Vnet","Result:"+ Result.Result+"  "+Result.ErrorDescription+"Count:"+this.TranslationCount.ToString()+"---Amount:"+(amount*100).ToString()+"  date:"+StartDate.ToString()+"~"+EndDate.ToString());

                                   if (Result.Result==0)

                                          lastupdate= DateTime.Now;

                            }

                            catch (Exception err)

                            {

                                   EventLog.WriteEntry(ServiceName +" Vnet","Error:"+"  "+err.Message);

                            }

                     }

              }

             

实际运行中发现,       EventLog.WriteEntry(ServiceName +"Event","timer started 1"); 运行正确,但是timer1_Tick中的代码并没有运行。

后来分析发现,工程的Refences中引用了VNetPSO.dll,但是没有把相应的文件copy,到相应目录。也就是说,运行时找不到此文件。

观察代码可知,引用VNetPSO.dll部分的代码只存在于timer1_Tick中。复制VNetPSO.dll到正确位置,问题排除。

由此发现.net所谓即时编译的一些特性。

InitializeComponent()中,可看到this.timer1.Elapsed += new  lapsedEventHandler(timer1_Tick);按照.net的即时编译的思路,开始认为这段代码会导致timer1_Tick被编译。但是如果是这样的顺序,在InitializeComponent中就会出现错误,导致程序不能正常运行。_那么OnStartEventLog.WriteEntry(ServiceName +"Event","timer started 1");

也就不可能运行了。

     所以,timer1_Tick实际是在Timer第一次触发的时候才被编译的。上面程序的例子中,就是在timer1启动了6秒之后。这时候发现VNetPSO.dll不存在,故此这部分代码被编译器忽略。也就造成了最开始出现的情况。

当然,前面只是一些推测,并没有方法能得到可靠的验证。但是,我认为推测应该基本合理。

至少,可以推测这么几个事实:

1 .net中的代码只有实际用到才会编译,除非强制进行预编译。

2 由于以上机制定时器变得更加不可靠,因为在定时器第一次触发的瞬间会导致编译,对于要求时间很高的程序可能会导致错过第一次执行的时间。

相关文章:
blog comments powered by Disqus
CC License. Some rights reserved.
署名·非商业用途·保持一致
本站之所有未作特别说明的内容均使用 创作共用协议.
POWERED_BY_MT_3.2