欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

C#中timer類(lèi)的三種不同用法(含timer為什么只執(zhí)行了一次)

admin
2024年1月2日 10:46 本文熱度 796

1、System.Windows.Forms.Timer  

實(shí)現(xiàn)按用戶(hù)定義的時(shí)間間隔引發(fā)事件的計(jì)時(shí)器。此計(jì)時(shí)器最宜用于 Windows 窗體應(yīng)用程序中,并且必須在窗口中使用。


2、System.Threading.Timer  

提供以指定的時(shí)間間隔執(zhí)行方法的機(jī)制。無(wú)法繼承此類(lèi)。


3、System.Timers.Timer  

在應(yīng)用程序中生成定期事件。 

這三個(gè)定時(shí)器位于不同的命名空間內(nèi),上面大概介紹了3個(gè)定時(shí)器的用途,其中第一個(gè)是只能在Windows窗體中使用的控件。

在.NET1.1里面,第3個(gè)System.Timers.Timer,也是可以拖拽使用,而.NET2.0開(kāi)始取消了,只能手動(dòng)編寫(xiě)代碼。而后2個(gè)沒(méi)有限制制。


下面通過(guò)具體的列子來(lái)看3個(gè)Timer的使用和區(qū)別

一 、System.Windows.Forms.Timer

#region

System.Windows.Forms.Timer

public partial class Form1 : Form

{

    public Form1()

    {

        InitializeComponent();

    }

    int num = 0;

    private void Form_Timer_Tick(object sender, EventArgs e)

    {

        label1.Text = (++num).ToString();

        Thread.Sleep(3000);

    }

    private void button1_Click(object sender, EventArgs e)

    {

        Form_Timer.Start();

    }

    private void button2_Click(object sender, EventArgs e)

    {

        Form_Timer.Stop();

    }

}

#endregion

上面這個(gè)是一個(gè)很簡(jiǎn)單的功能,在Form窗體上拖了一個(gè)System.Windows.Forms.Timer控件名字為Form_Timer,在屬性窗中把Enable屬性設(shè)置為T(mén)ure,Interval是定時(shí)器的間隔時(shí)間。雙擊這個(gè)控件就可以看到 Form_Timer_Tick方法。

在這個(gè)方法中,我們讓她不停的加一個(gè)數(shù)字并顯示在窗體上,2個(gè)按鈕提供了對(duì)計(jì)時(shí)器的控制功能。執(zhí)行的時(shí)候你去點(diǎn)擊其他窗體在回來(lái),你會(huì)發(fā)現(xiàn)我們的窗體失去響應(yīng)了。

因?yàn)槲覀冞@里使用Thread.Sleep(3000); 讓當(dāng)前線(xiàn)程掛起,而UI失去相應(yīng),說(shuō)明了這里執(zhí)行時(shí)候采用的是單線(xiàn)程。也就是執(zhí)行定時(shí)器的線(xiàn)程就是UI線(xiàn)程。Timer 用于以用戶(hù)定義的事件間隔觸發(fā)事件。

Windows 計(jì)時(shí)器是為單線(xiàn)程環(huán)境設(shè)計(jì)的,其中,UI 線(xiàn)程用于執(zhí)行處理。它要求用戶(hù)代碼有一個(gè)可用的 UI 消息泵,而且總是在同一個(gè)線(xiàn)程中操作,或者將調(diào)用封送到另一個(gè)線(xiàn)程。

在Timer內(nèi)部定義的了一個(gè)Tick事件,我們前面雙擊這個(gè)控件時(shí)實(shí)際是增加了一行代碼。

this.Form_Timer.Tick += new System.EventHandler(this.Form_Timer_Tick);  

然后Windows將這個(gè)定時(shí)器與調(diào)用線(xiàn)程關(guān)聯(lián)(UI線(xiàn)程)。當(dāng)定時(shí)器觸發(fā)時(shí),Windows把一個(gè)定時(shí)器消息插入到線(xiàn)程消息隊(duì)列中。調(diào)用線(xiàn)程執(zhí)行一個(gè)消息泵提取消息,然后發(fā)送到回調(diào)方法中(這里的Form_Timer_Tick方法)。

而這些都是單線(xiàn)程進(jìn)行了,所以在執(zhí)行回調(diào)方法時(shí)UI會(huì)假死。所以使用這個(gè)控件不宜執(zhí)行計(jì)算受限或IO受限的代碼,因?yàn)檫@樣容易導(dǎo)致界面假死,而應(yīng)該使用多線(xiàn)程調(diào)用的Timer。

另外要注意的是這個(gè)控件時(shí)間精度不高,精度限定為 55 毫秒。


二、System.Timers.Timer

接下來(lái)就看下另一個(gè)Timer,我們用它來(lái)改寫(xiě)上面的程序

#region

System.Windows.Forms.Timer

public partial class Form1 : Form

{

    public Form1()

    {

        InitializeComponent();

    }

    int num = 0;

    DateTime time1 = new DateTime();

    DateTime time2 = new DateTime();

    //定義Timer   

    System.Timers.Timer Timers_Timer = new System.Timers.Timer();

    private void button1_Click(object sender, EventArgs e)

    {

        //手動(dòng)設(shè)置Timer,開(kāi)始執(zhí)行     

        Timers_Timer.Interval = 20;

        Timers_Timer.Enabled = true;

        Timers_Timer.Elapsed += new System.Timers.ElapsedEventHandler(Timers_Timer_Elapsed);

        time1 = DateTime.Now;

    }

    void Timers_Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)

    {

        label1.Text = Convert.ToString((++num)); //顯示到lable         

        Thread.Sleep(3000);

    }

    private void button2_Click(object sender, EventArgs e)

    {

        //停止執(zhí)行

        Timers_Timer.Enabled = false;

        time2 = DateTime.Now;

        MessageBox.Show(Convert.ToString(time2 - time1));

    }

}

#endregion

我們可以看到這個(gè)代碼和前面使用Form.Timer的基本相同,不同的是我們是手動(dòng)定義的對(duì)象,而不是通過(guò)拉控件。他也有Interval ,Enabled 等屬性,作用和第一是一樣的。

不同的是他的事件名為Elapsed ,但是和上面的Tick一樣,綁定一個(gè)委托的方法。只是這里我們是手動(dòng)完成的。另外不同之處是Form.Timer我們可以用Stop和Start方法控制,而這里是通過(guò)Enable屬性控制。

但實(shí)際上也可以用Stop和Start方法,內(nèi)部也是通過(guò)他自己的Enable來(lái)控制的。

  最大的不同就是上面的代碼在調(diào)試時(shí)會(huì)報(bào)錯(cuò),提示你"線(xiàn)程間操作無(wú)效: 從不是創(chuàng)建控件“l(fā)abel1”的線(xiàn)程訪(fǎng)問(wèn)它。"但如果你不調(diào)試直接運(yùn)行是OK的,而且運(yùn)行時(shí)你去拖動(dòng)窗體會(huì)發(fā)現(xiàn)沒(méi)有出現(xiàn)假死。

從這里我們就可以知道這里的Timer的創(chuàng)建線(xiàn)程和執(zhí)行線(xiàn)程不是同一個(gè)線(xiàn)程。也就是使用了多線(xiàn)程。Timer的創(chuàng)建線(xiàn)程是UI線(xiàn)程,而執(zhí)行線(xiàn)程是TheardPool中的線(xiàn)程,所以不會(huì)假死,但調(diào)試的時(shí)候會(huì)報(bào)錯(cuò),因?yàn)榉强丶膭?chuàng)建線(xiàn)程不能操作控件。

但你可以直接運(yùn)行,這里是VS05做了手腳。解決辦法很多,用delegate.BeginInvoke()等等。這里介紹特有的一種方法,設(shè)置Timer的SynchronizingObject屬性,Timers_Timer.SynchronizingObject = label1;

這樣調(diào)試運(yùn)行時(shí)就不會(huì)報(bào)錯(cuò)了,但是設(shè)置了這個(gè)屬性Timer就編程單線(xiàn)程調(diào)用了,就基本和第一個(gè)完全一樣了。

      /// 在timer中使用SynchronizingObject的原因(tangtao_xp的注解)

        /// 請(qǐng)參考https://msdn.microsoft.com/en-us//library/system.timers.timer.synchronizingobject

        /// 1.如果SynchronizingObject為null,timer的Elapsed事件會(huì)默認(rèn)由線(xiàn)程池進(jìn)行處理

        /// 2.如果timer的Elapsed事件要在windows Form等UI元件中處理,就會(huì)出現(xiàn)UI線(xiàn)程訪(fǎng)問(wèn)線(xiàn)程池情況

        /// 此時(shí)會(huì)引發(fā)錯(cuò)誤和異常;將SynchronizingObject設(shè)置成要處理timer的Elapsed事件的UI元件,

        /// 該timer就會(huì)由該UI元件的線(xiàn)程創(chuàng)建,從而避免異常。


三 、System.Threading.Timer

繼續(xù)用這個(gè)對(duì)象改造程序。

#region 

System.Windows.Forms.Timer

public partial class Form1 : Form

{

    public Form1()

    {

        InitializeComponent();

    }

    int num = 0;

    DateTime time1 = new DateTime();

    DateTime time2 = new DateTime();

    System.Threading.Timer Thread_Time;

    private void button1_Click(object sender, EventArgs e)

    {

        //啟動(dòng)         

        Thread_Time = new System.Threading.Timer(Thread_Timer_Method, null, 0, 20);

        time1 = DateTime.Now;

    }

    void Thread_Timer_Method(object o)

    {

        label1.Text = Convert.ToString((++num));

        System.Threading.Thread.Sleep(3000);

    }

    private void button2_Click(object sender, EventArgs e)

    {

        //停止         

        Thread_Time.Dispose();

        time2 = DateTime.Now;

        MessageBox.Show(Convert.ToString(time2 - time1));

    }

}

#endregion

用Threading.Timer時(shí)的方法,和前面就不太相同了,所以的參數(shù)全部在構(gòu)造函數(shù)中進(jìn)行了設(shè)置,而且可以設(shè)置啟動(dòng)時(shí)間。而且沒(méi)有提供start和stop方法來(lái)控制計(jì)時(shí)器。

而且是以一種回調(diào)方法的方式實(shí)現(xiàn),而不是通過(guò)事件來(lái)實(shí)現(xiàn)的。他們之間還是有區(qū)別的。我們只有銷(xiāo)毀掉對(duì)象來(lái)停止他。

當(dāng)你運(yùn)行時(shí),你會(huì)發(fā)現(xiàn)他和前面的Timers.Timer一樣,是多線(xiàn)程的,主要表現(xiàn)在不會(huì)假死,調(diào)試運(yùn)行報(bào)錯(cuò)。但跟讓你奇怪的是,我們的代碼竟然無(wú)法讓她停止下來(lái)。

調(diào)用了Dispose方法沒(méi)有用。問(wèn)題在那?然后有進(jìn)行了測(cè)試,修改了間隔時(shí)間為100,200,500,1000,3000,4000。

這幾種情況。發(fā)現(xiàn)當(dāng)間隔為500ms以上是基本馬上就停止了。而間隔時(shí)間相對(duì)執(zhí)行時(shí)間越短,繼續(xù)執(zhí)行的時(shí)間越長(zhǎng)。這應(yīng)該是在間隔時(shí)間小于執(zhí)行時(shí)間時(shí)多個(gè)線(xiàn)程運(yùn)行造成的。因?yàn)樗械木€(xiàn)程不是同時(shí)停止的。間隔越短,線(xiàn)程越多,所以執(zhí)行次數(shù)越多。

最后來(lái)看下這個(gè)對(duì)象另外一個(gè)特殊的地方。

static void Main()

{

    Timer t = new Timer(Test, null, 0, 1000);

    Console.ReadLine();

}

public static void Test(object o)

{

    Console.WriteLine("hello world");

    GC.Collect();

}

這段代碼會(huì)輸出什么結(jié)果呢?默認(rèn)情況他只輸出一次,就停止了。為什么呢?根據(jù)上面說(shuō)的,當(dāng)定義對(duì)象t,執(zhí)行代碼后,進(jìn)行了強(qiáng)制垃圾回收,因?yàn)閠在Main中沒(méi)有其他引用,所以被回收掉了。

但是如果我們把編譯器的”優(yōu)化“項(xiàng)取消掉,在看看情況。程序進(jìn)然一直在輸出。為什么執(zhí)行垃圾回收卻沒(méi)有被回收呢?因?yàn)檫@個(gè)禁用優(yōu)化選項(xiàng),t的聲明周期被擴(kuò)展到了方法結(jié)束。所以一直執(zhí)行。

因?yàn)榫幾g器默認(rèn)是優(yōu)化的,所以我們必須保證Timer對(duì)象一直被引用,而避免被垃圾回收。所以我們可以在編譯器打開(kāi)優(yōu)化的情況下,在Main函數(shù)最后加上t=null保證回收前被引用,但你發(fā)現(xiàn),這樣是沒(méi)用的。

因?yàn)镴IT編譯器優(yōu)化后會(huì)吧t=null直接刪除,所以我們用t.Dispose(),就可以達(dá)到目的。在我們進(jìn)行垃圾回收時(shí),CLR發(fā)現(xiàn)t還有被引用,還沒(méi)執(zhí)行Dispose所以不會(huì)被回收。

是以Threading.Timer有時(shí)候會(huì)出現(xiàn)運(yùn)行一次就停止或者是銷(xiāo)毀了還在運(yùn)行的情況,而且和編譯器優(yōu)化也有關(guān),所以使用時(shí)要注意。

最后看下MSDN的描述: 只要在使用 Timer,就必須保留對(duì)它的引用。對(duì)于任何托管對(duì)象,如果沒(méi)有對(duì) Timer 的引用,計(jì)時(shí)器會(huì)被垃圾回收。即使 Timer 仍處在活動(dòng)狀態(tài),也會(huì)被回收。當(dāng)不再需要計(jì)時(shí)器時(shí),請(qǐng)使用 Dispose 方法釋放計(jì)時(shí)器持有的資源。

如果希望在計(jì)時(shí)器被釋放時(shí)接收到信號(hào),請(qǐng)使用接受 WaitHandle 的 Dispose(WaitHandle) 方法重載。計(jì)時(shí)器已被釋放后,WaitHandle 便終止。


總結(jié):

  System.Threading.Timer 是一個(gè)簡(jiǎn)單的輕量計(jì)時(shí)器,它使用回調(diào)方法并由線(xiàn)程池線(xiàn)程提供服務(wù)。不建議將其用于 Windows 窗體,因?yàn)槠浠卣{(diào)不在用戶(hù)界面線(xiàn)程上進(jìn)行。System.Windows.Forms.Timer 是用于 Windows 窗體的更佳選擇。

  要獲取基于服務(wù)器的計(jì)時(shí)器功能,可以考慮使用 System.Timers.Timer,它可以引發(fā)事件并具有其他功能。

  在《CLR Via C#》中講多線(xiàn)程時(shí)有提到這3個(gè)計(jì)時(shí)器,但作者說(shuō)System.Timers.Timer是對(duì)System.Threading.Timer的報(bào)裝,不推薦使用,但是在我的WEB項(xiàng)目中的Application_Start中我還是使用的這個(gè)而不是Threading.Timer,因?yàn)槭褂肨hreading.Timer時(shí)只執(zhí)行了一次就不在執(zhí)行了。

  對(duì)于計(jì)時(shí)器在B/S結(jié)構(gòu)中的使用就復(fù)雜一些,一般我們把計(jì)時(shí)器放在Application_OnStart中,這樣全局維護(hù)一個(gè)計(jì)時(shí)器,可以進(jìn)行定期備份數(shù)據(jù)庫(kù),定期維護(hù)用戶(hù)等操作,而且方法寫(xiě)作靜態(tài)的,以免被垃圾回收。

  而不建議在一般的aspx頁(yè)面中使用,因?yàn)榉?wù)器端的定時(shí)器對(duì)用戶(hù)這樣意義不大,完全可以使用JS代替。而且這個(gè)頁(yè)面的每個(gè)請(qǐng)求都可能引入一個(gè)新的定時(shí)器,導(dǎo)致系統(tǒng)崩潰。

  另外,定時(shí)器是ASP.NET進(jìn)程,IIS有關(guān),所以對(duì)用重要的執(zhí)行任務(wù),還是建議寫(xiě)成服務(wù)或獨(dú)立程序放在服務(wù)器上執(zhí)行好了。

  System.Windows.Forms.Timer是應(yīng)用于WinForm中的,它是通過(guò)Windows消息機(jī)制實(shí)現(xiàn)的,類(lèi)似于VB或Delphi中的Timer控件,內(nèi)部使用API  SetTimer實(shí)現(xiàn)的。它的主要缺點(diǎn)是計(jì)時(shí)不精確,而且必須有消息循環(huán),Console  Application(控制臺(tái)應(yīng)用程序)無(wú)法使用。   

  System.Timers.Timer和System.Threading.Timer非常類(lèi)似,它們是通過(guò).NET  Thread  Pool實(shí)現(xiàn)的,輕量,計(jì)時(shí)精確,對(duì)應(yīng)用程序、消息沒(méi)有特別的要求。System.Timers.Timer還可以應(yīng)用于WinForm,完全取代上面的Timer控件。它們的缺點(diǎn)是不支持直接的拖放,需要手工編碼。 


該文章在 2024/1/3 22:24:26 編輯過(guò)
關(guān)鍵字查詢(xún)
相關(guān)文章
正在查詢(xún)...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專(zhuān)業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車(chē)隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類(lèi)企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷(xiāo)售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶(hù)的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved