日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#的Timer解析(转)

發(fā)布時間:2023/12/31 C# 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#的Timer解析(转) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?

在C#里現(xiàn)在有3個Timer類:

?System.Windows.Forms.Timer
?System.Threading.Timer
?System.Timers.Timer
這三個Timer我想大家對System.Windows.Forms.Timer已經(jīng)很熟悉了,唯一我要說的就是這個Timer在激發(fā)Timer.Tick事件的時候,事件的處理函數(shù)是在程序主線程上執(zhí)行的,所以在WinForm上面用這個Timer很方便,因為在From上的所有控件都是在程序主線程上創(chuàng)建的,那么在Tick的處理函數(shù)中可以對Form上的所有控件進行操作,不會造成WinForm控件的線程安全問題。

1、Timer運行的核心都是System.Threading.ThreadPool

在這里要提到ThreadPool(線程池)是因為,System.Threading.Timer 和System.Timers.Timer運行的核心都是線程池,Timer每到間隔時間后就會激發(fā)響應(yīng)事件,因此要申請線程來執(zhí)行對應(yīng)的響應(yīng)函數(shù),Timer將獲取線程的工作都交給了線程池來管理,每到一定的時間后它就去告訴線程池:“我現(xiàn)在激發(fā)了個事件要運行對應(yīng)的響應(yīng)函數(shù),麻煩你給我向操作系統(tǒng)要個線程,申請交給你了,線程分配下來了你就運行我給你的響應(yīng)函數(shù),沒分配下來先讓響應(yīng)函數(shù)在這兒排隊(操作系統(tǒng)線程等待隊列)”,消息已經(jīng)傳遞給線程池了,Timer也就不管了,因為它還有其他的事要做(每隔一段時間它又要激發(fā)事件),至于提交的請求什么時候能夠得到滿足,要看線程池當前的狀態(tài):

?1、如果線程池現(xiàn)在有線程可用,那么申請馬上就可以得到滿足,有線程可用又可以分為兩種情況:
?<1>線程池現(xiàn)在有空閑線程,現(xiàn)在馬上就可以用
?<2>線程池本來現(xiàn)在沒有線程了,但是剛好申請到達的時候,有線程運行完畢釋放了,那么申請就可以用別人釋放的線程。
?這兩種情況情況就如同你去游樂園玩賽車,如果游樂園有10輛車,現(xiàn)在有3個人在玩,那么還剩7輛車,你去了當然可以選一輛開。另外還有一種情況就是你到達游樂園前10輛車都在開,但是你運氣很好,剛到游樂園就有人不玩了,正好你坐上去就可以接著開。
?2、如果現(xiàn)在線程池現(xiàn)在沒有線程可用,也分為兩種情況:
?<1>線程池現(xiàn)有線程數(shù)沒有達到設(shè)置的最大工作線程數(shù),那么隔半秒鐘.net framework就會向操作系統(tǒng)申請一個新的線程(為避免向線程分配不必要的堆棧空間,線程池按照一定的時間間隔創(chuàng)建新的空閑線程。該時間間隔目前為半秒,但它在 .NET Framework 的以后版本中可能會更改)。
?<2>線程池現(xiàn)有工作線程數(shù)達到了設(shè)置的最大工作線程數(shù),那么申請只有在等待隊列一直等下去,直到有線程執(zhí)行完任務(wù)后被釋放。
?那么上面提到了線程池有最大工作線程數(shù),其實還有最小空閑線程數(shù),那么這兩個關(guān)鍵字是什么意思呢:

?1、最大工作線程數(shù):實際上就是指的線程池能夠向操作系統(tǒng)申請的最大線程數(shù),這個值在.net framework中有默認值,這個默認值是根據(jù)你計算機的配置來的,當人你可以用ThreadPool.GetMaxThreads返回線程池當前最大工作線程數(shù),你也可以同ThreadPool.SetMaxThreads設(shè)置線程池當前最大工作線程數(shù)。
?2、最小空閑線程數(shù):是指在程序開始后,線程池就默認向操作系統(tǒng)要最小空閑線程數(shù)個線程,另外這也是線程池維護的空閑線程數(shù)(如果線程池最小空閑線程數(shù)為3,當前因為一些線程執(zhí)行完任務(wù)被釋放,線程池現(xiàn)在實際上有10個空閑線程,那么線程池會讓操作系統(tǒng)釋放多余的7個線程,而只維持3個空閑線程供程序使用),因為上面說了,在執(zhí)行程序的時候在要線程池申請線程有半秒的延遲時間,這也會影響程序的性能,所以把握好這個值很重要,用樣你可以用ThreadPool.GetMinThreads返回線程池當前最小空閑線程數(shù),你也可以同ThreadPool.SetMinThreads設(shè)置線程池當前最小空閑線程數(shù)。
下面是我給的例子,這個例子讓線程池申請800個線程,其中設(shè)置最大工作線程數(shù)為500,800個線程任務(wù)每個都要執(zhí)行100000000毫秒目的是讓線程不會釋放,并且讓用戶選擇,是否預(yù)先申請500個空閑線程免受那半秒鐘的延遲時間,其結(jié)果可想而知當線程申請到500的時候,線程池達到了最大工作線程數(shù),剩余的300個申請進入漫長的等待時間:

view plaincopy to clipboardprint?
01./***************************************************?
02. * 項目:測試線程池?
03. * 描述:驗證線程池的最大工作線程數(shù)和最小空閑線程數(shù)?
04. * 作者:@PowerCoder?
05. * 日期:2010-2-22?
06.***************************************************/?
07.?
08.using System;??
09.using System.Collections.Generic;??
10.using System.Text;??
11.using System.Threading;??
12.?
13.namespace ConsoleApplication1??
14.{??
15.??? class Program??
16.??? {??
17.??????? static int i=1;??
18.??????? static int MaxThreadCount = 800;??
19.?
20.??????? static void OutPut(object obj)??
21.??????? {??
22.??????????? Console.Write("\r申請了:{0}個工作線程",i);??
23.??????????? i++;??
24.??????????? Thread.Sleep(100000000);//設(shè)置一個很大的等待時間,讓每個申請的線程都一直執(zhí)行??
25.??????? }??
26.?
27.??????? static void Main(string[] args)??
28.??????? {??
29.??????????? int j;??
30.??????????????
31.??????????? Console.Write("是否先申請500個空閑線程以保證前500個線程在線程池中開始就有線程用(Y/N)?");//如果這里選擇N,那么前兩個任務(wù)是用的線程池默認空閑線程(可以用ThreadPool.GetMinThreads得到系統(tǒng)默認最小空閑線程數(shù)為2)申請立即得到滿足,然而由于每個線程等待時間非常大都不會釋放當前自己持有的線程,因此線程池中已無空閑線程所用,后面的任務(wù)需要在線程池中申請新的線程,那么新申請的每個線程在線程池中都要隔半秒左右的時間才能得到申請(原因請見下面的注釋)??
32.??????????? string key = Console.ReadLine();??
33.??????????? if(key.ToLower()=="y")??
34.??????????????? ThreadPool.SetMinThreads(500, 10);//設(shè)置最大空閑線程為500,就好像我告訴系統(tǒng)給我預(yù)先準備500個線程我來了就直接用,因為這樣就不用現(xiàn)去申請了,在線程池中每申請一個新的線程.NET Framework 會安排一個間隔時間,目前是半秒,以后的版本MS有可能會改??
35.??????????????
36.??????????? int a, b;??
37.??????????? ThreadPool.GetMaxThreads(out a,out b);??
38.??????????? Console.WriteLine("線程池默認最大工作線程數(shù):" + a.ToString() + "???? 默認最大異步 I/O 線程數(shù):" + b.ToString());??
39.??????????? Console.WriteLine("需要向系統(tǒng)申請" + MaxThreadCount.ToString()+"個工作線程");??
40.?
41.??????????? for (j = 0; j <= MaxThreadCount-1; j++)//由于ThreadPool.GetMaxThreads返回的默認最大工作線程數(shù)為500(這個值要根據(jù)你計算機的配置來決定),那么向線程池申請大于500個線程的時候,500之后的線程會進入線程池的等待隊列,等待前面500個線程某個線程執(zhí)行完后來喚醒等待隊列的某個線程???
42.??????????? {??
43.??????????????? ThreadPool.QueueUserWorkItem(new WaitCallback(OutPut));??
44.??????????????? Thread.Sleep(10);??
45.??????????? }??
46.?
47.??????????? Console.ReadLine();??
48.??????? }??
49.??? }??
50.}?
/***************************************************
?* 項目:測試線程池
?* 描述:驗證線程池的最大工作線程數(shù)和最小空閑線程數(shù)
?* 作者:@PowerCoder
?* 日期:2010-2-22
***************************************************/

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace ConsoleApplication1
{
??? class Program
??? {
??????? static int i=1;
??????? static int MaxThreadCount = 800;

??????? static void OutPut(object obj)
??????? {
??????????? Console.Write("\r申請了:{0}個工作線程",i);
??????????? i++;
??????????? Thread.Sleep(100000000);//設(shè)置一個很大的等待時間,讓每個申請的線程都一直執(zhí)行
??????? }

??????? static void Main(string[] args)
??????? {
??????????? int j;
???????????
??????????? Console.Write("是否先申請500個空閑線程以保證前500個線程在線程池中開始就有線程用(Y/N)?");//如果這里選擇N,那么前兩個任務(wù)是用的線程池默認空閑線程(可以用ThreadPool.GetMinThreads得到系統(tǒng)默認最小空閑線程數(shù)為2)申請立即得到滿足,然而由于每個線程等待時間非常大都不會釋放當前自己持有的線程,因此線程池中已無空閑線程所用,后面的任務(wù)需要在線程池中申請新的線程,那么新申請的每個線程在線程池中都要隔半秒左右的時間才能得到申請(原因請見下面的注釋)
??????????? string key = Console.ReadLine();
??????????? if(key.ToLower()=="y")
??????????????? ThreadPool.SetMinThreads(500, 10);//設(shè)置最大空閑線程為500,就好像我告訴系統(tǒng)給我預(yù)先準備500個線程我來了就直接用,因為這樣就不用現(xiàn)去申請了,在線程池中每申請一個新的線程.NET Framework 會安排一個間隔時間,目前是半秒,以后的版本MS有可能會改
???????????
??????????? int a, b;
??????????? ThreadPool.GetMaxThreads(out a,out b);
??????????? Console.WriteLine("線程池默認最大工作線程數(shù):" + a.ToString() + "???? 默認最大異步 I/O 線程數(shù):" + b.ToString());
??????????? Console.WriteLine("需要向系統(tǒng)申請" + MaxThreadCount.ToString()+"個工作線程");

??????????? for (j = 0; j <= MaxThreadCount-1; j++)//由于ThreadPool.GetMaxThreads返回的默認最大工作線程數(shù)為500(這個值要根據(jù)你計算機的配置來決定),那么向線程池申請大于500個線程的時候,500之后的線程會進入線程池的等待隊列,等待前面500個線程某個線程執(zhí)行完后來喚醒等待隊列的某個線程
??????????? {
??????????????? ThreadPool.QueueUserWorkItem(new WaitCallback(OutPut));
??????????????? Thread.Sleep(10);
??????????? }

??????????? Console.ReadLine();
??????? }
??? }
}

2、System.Threading.Timer

談完了線程池,就可以開始討論Timer,這里我們先從System.Threading.Timer開始,System.Threading.Timer的作用就是每到間隔時間后激發(fā)響應(yīng)事件并執(zhí)行相應(yīng)函數(shù),執(zhí)行響應(yīng)函數(shù)要向線程池申請線程,當然申請中會遇到一些情況在上面我們已經(jīng)說了。值得注意的一點就是System.Threading.Timer在創(chuàng)建對象后立即開始執(zhí)行,比如System.Threading.Timer timer = new System.Threading.Timer(Excute, null, 0, 10);這句執(zhí)行完后每隔10毫秒就執(zhí)行Excute函數(shù)不需要啟動什么的。下面就舉個例子,我先把代碼貼出來:

view plaincopy to clipboardprint?
01.using System;??
02.using System.Collections.Generic;??
03.using System.Text;??
04.using System.Threading;??
05.using System.Diagnostics;??
06.?
07.namespace ConsoleApplication1??
08.{??
09.??? class UnSafeTimer??
10.??? {??
11.??????? static int i = 0;??
12.??????? static System.Threading.Timer timer;??
13.??????? static object mylock = new object();??
14.??????? static int sleep;??
15.??????? static bool flag;??
16.??????? public static Stopwatch sw = new Stopwatch();??
17.?
18.??????? static void Excute(object obj)??
19.??????? {??
20.??????????? Thread.CurrentThread.IsBackground = false;??
21.??????????? int c;??
22.?
23.??????????? lock (mylock)??
24.??????????? {??
25.??????????????? i++;??
26.??????????????? c = i;??
27.??????????? }??
28.?
29.??????????? if (c == 80)??
30.??????????? {??
31.??????????????? timer.Dispose();//執(zhí)行Dispose后Timer就不會再申請新的線程了,但是還是會給Timmer已經(jīng)激發(fā)的事件申請線程??
32.??????????????? sw.Stop();??
33.??????????? }??
34.?
35.??????????? if (c < 80)??
36.??????????????? Console.WriteLine("Now:" + c.ToString());??
37.??????????? else?
38.??????????? {??
39.??????????????? Console.WriteLine("Now:" + c.ToString()+"-----------Timer已經(jīng)Dispose耗時:"+sw.ElapsedMilliseconds.ToString()+"毫秒");??
40.??????????? }??
41.?
42.??????????? if (flag)??
43.??????????? {??
44.??????????????? Thread.Sleep(sleep);//模擬花時間的代碼??
45.??????????? }??
46.??????????? else?
47.??????????? {??
48.??????????????? if(i<=80)??
49.??????????????????? Thread.Sleep(sleep);//前80次模擬花時間的代碼??
50.??????????? }??
51.??????? }??
52.?
53.??????? public static void Init(int p_sleep,bool p_flag)??
54.??????? {??
55.??????????? sleep = p_sleep;??
56.??????????? flag = p_flag;??
57.??????????? timer = new System.Threading.Timer(Excute, null, 0, 10);??
58.??????? }??
59.??? }??
60.?
61.??? class SafeTimer??
62.??? {??
63.??????? static int i = 0;??
64.??????? static System.Threading.Timer timer;??
65.?
66.??????? static bool flag = true;??
67.??????? static object mylock = new object();??
68.?
69.??????? static void Excute(object obj)??
70.??????? {??
71.??????????? Thread.CurrentThread.IsBackground = false;??
72.?
73.??????????? lock (mylock)??
74.??????????? {??
75.??????????????? if (!flag)??
76.??????????????? {??
77.??????????????????? return;??
78.??????????????? }??
79.?
80.??????????????? i++;??
81.?
82.??????????????? if (i == 80)??
83.??????????????? {??
84.??????????????????? timer.Dispose();??
85.??????????????????? flag = false;??
86.??????????????? }??
87.??????????????? Console.WriteLine("Now:" + i.ToString());??
88.??????????? }??
89.?
90.??????????? Thread.Sleep(1000);//模擬花時間的代碼??
91.??????? }??
92.?
93.??????? public static void Init()??
94.??????? {??
95.??????????? timer = new System.Threading.Timer(Excute, null, 0, 10);??
96.??????? }??
97.??? }??
98.?
99.??? class Program??
100.??? {??
101.??????? static void Main(string[] args)??
102.??????? {??
103.??????????? Console.Write("是否使用安全方法(Y/N)?");??
104.??????????? string key = Console.ReadLine();??
105.??????????? if (key.ToLower() == "y")??
106.??????????????? SafeTimer.Init();??
107.??????????? else?
108.??????????? {??
109.??????????????? Console.Write("請輸入Timmer響應(yīng)事件的等待時間(毫秒):");//這個時間直接決定了前80個任務(wù)的執(zhí)行時間,因為等待時間越短,每個任務(wù)就可以越快執(zhí)行完,那么80個任務(wù)中就有越多的任務(wù)可以用到前面任務(wù)執(zhí)行完后釋放掉的線程,也就有越多的任務(wù)不必去線程池申請新的線程避免多等待半秒鐘的申請時間??
110.??????????????? string sleep = Console.ReadLine();??
111.??????????????? Console.Write("申請了80個線程后Timer剩余激發(fā)的線程請求是否需要等待時間(Y/N)?");//這里可以發(fā)現(xiàn)選Y或者N只要等待時間不變,最終Timer激發(fā)線程的次數(shù)都相近,說明Timer的確在執(zhí)行80次的Dispose后就不再激發(fā)新的線程了??
112.??????????????? key = Console.ReadLine();??
113.??????????????? bool flag = false;??
114.??????????????? if (key.ToLower() == "y")??
115.??????????????? {??
116.??????????????????? flag = true;??
117.??????????????? }??
118.?
119.??????????????? UnSafeTimer.sw.Start();??
120.??????????????? UnSafeTimer.Init(Convert.ToInt32(sleep), flag);??
121.??????????? }??
122.?
123.??????????? Console.ReadLine();??
124.??????? }??
125.??? }??
126.}?
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;

namespace ConsoleApplication1
{
??? class UnSafeTimer
??? {
??????? static int i = 0;
??????? static System.Threading.Timer timer;
??????? static object mylock = new object();
??????? static int sleep;
??????? static bool flag;
??????? public static Stopwatch sw = new Stopwatch();

??????? static void Excute(object obj)
??????? {
??????????? Thread.CurrentThread.IsBackground = false;
??????????? int c;

??????????? lock (mylock)
??????????? {
??????????????? i++;
??????????????? c = i;
??????????? }

??????????? if (c == 80)
??????????? {
??????????????? timer.Dispose();//執(zhí)行Dispose后Timer就不會再申請新的線程了,但是還是會給Timmer已經(jīng)激發(fā)的事件申請線程
??????????????? sw.Stop();
??????????? }

??????????? if (c < 80)
??????????????? Console.WriteLine("Now:" + c.ToString());
??????????? else
??????????? {
??????????????? Console.WriteLine("Now:" + c.ToString()+"-----------Timer已經(jīng)Dispose耗時:"+sw.ElapsedMilliseconds.ToString()+"毫秒");
??????????? }

??????????? if (flag)
??????????? {
??????????????? Thread.Sleep(sleep);//模擬花時間的代碼
??????????? }
??????????? else
??????????? {
??????????????? if(i<=80)
??????????????????? Thread.Sleep(sleep);//前80次模擬花時間的代碼
??????????? }
??????? }

??????? public static void Init(int p_sleep,bool p_flag)
??????? {
??????????? sleep = p_sleep;
??????????? flag = p_flag;
??????????? timer = new System.Threading.Timer(Excute, null, 0, 10);
??????? }
??? }

??? class SafeTimer
??? {
??????? static int i = 0;
??????? static System.Threading.Timer timer;

??????? static bool flag = true;
??????? static object mylock = new object();

??????? static void Excute(object obj)
??????? {
??????????? Thread.CurrentThread.IsBackground = false;

??????????? lock (mylock)
??????????? {
??????????????? if (!flag)
??????????????? {
??????????????????? return;
??????????????? }

??????????????? i++;

??????????????? if (i == 80)
??????????????? {
??????????????????? timer.Dispose();
??????????????????? flag = false;
??????????????? }
??????????????? Console.WriteLine("Now:" + i.ToString());
??????????? }

??????????? Thread.Sleep(1000);//模擬花時間的代碼
??????? }

??????? public static void Init()
??????? {
??????????? timer = new System.Threading.Timer(Excute, null, 0, 10);
??????? }
??? }

??? class Program
??? {
??????? static void Main(string[] args)
??????? {
??????????? Console.Write("是否使用安全方法(Y/N)?");
??????????? string key = Console.ReadLine();
??????????? if (key.ToLower() == "y")
??????????????? SafeTimer.Init();
??????????? else
??????????? {
??????????????? Console.Write("請輸入Timmer響應(yīng)事件的等待時間(毫秒):");//這個時間直接決定了前80個任務(wù)的執(zhí)行時間,因為等待時間越短,每個任務(wù)就可以越快執(zhí)行完,那么80個任務(wù)中就有越多的任務(wù)可以用到前面任務(wù)執(zhí)行完后釋放掉的線程,也就有越多的任務(wù)不必去線程池申請新的線程避免多等待半秒鐘的申請時間
??????????????? string sleep = Console.ReadLine();
??????????????? Console.Write("申請了80個線程后Timer剩余激發(fā)的線程請求是否需要等待時間(Y/N)?");//這里可以發(fā)現(xiàn)選Y或者N只要等待時間不變,最終Timer激發(fā)線程的次數(shù)都相近,說明Timer的確在執(zhí)行80次的Dispose后就不再激發(fā)新的線程了
??????????????? key = Console.ReadLine();
??????????????? bool flag = false;
??????????????? if (key.ToLower() == "y")
??????????????? {
??????????????????? flag = true;
??????????????? }

??????????????? UnSafeTimer.sw.Start();
??????????????? UnSafeTimer.Init(Convert.ToInt32(sleep), flag);
??????????? }

??????????? Console.ReadLine();
??????? }
??? }
}
?

這個例子包含了兩個Timer的類UnSafeTimer和SafeTimer,兩個類的代碼的大致意思就是使用Timer每隔10毫秒就執(zhí)行Excute函數(shù),Excute函數(shù)會顯示當前執(zhí)行的次數(shù),在80次的時候通過timer.Dispose()讓Timer停止不再激發(fā)響應(yīng)事件。

首先我們來分析下UnSafeTimer

class UnSafeTimer
{
??? static int i = 0;
??? static System.Threading.Timer timer;
??? static object mylock = new object();
??? static int sleep;
??? static bool flag;
??? public static Stopwatch sw = new Stopwatch();

??? static void Excute(object obj)
??? {
??????? Thread.CurrentThread.IsBackground = false;
??????? int c;

??????? lock (mylock)
??????? {
??????????? i++;
??????????? c = i;
??????? }

??????? if (c == 80)
??????? {
??????????? timer.Dispose();//執(zhí)行Dispose后Timer就不會再申請新的線程了,但是還是會給Timmer已經(jīng)激發(fā)的事件申請線程
??????????? sw.Stop();
??????? }

??????? if (c < 80)
??????????? Console.WriteLine("Now:" + c.ToString());
??????? else
??????? {
??????????? Console.WriteLine("Now:" + c.ToString() + "-----------Timer已經(jīng)Dispose耗時:" + sw.ElapsedMilliseconds.ToString() + "毫秒");
??????? }

??????? if (flag)
??????? {
??????????? Thread.Sleep(sleep);//模擬花時間的代碼
??????? }
??????? else
??????? {
??????????? if (i <= 80)
??????????????? Thread.Sleep(sleep);//前80次模擬花時間的代碼
??????? }
??? }

??? public static void Init(int p_sleep, bool p_flag)
??? {
??????? sleep = p_sleep;
??????? flag = p_flag;
??????? timer = new System.Threading.Timer(Excute, null, 0, 10);
??? }
}

你可以執(zhí)行試一試,在輸入是否執(zhí)行安全方法的時候選N,等待時間1000,申請了80個線程后Timer剩余激發(fā)的線程選N,本來想在80次的時候停下來,可是你會發(fā)現(xiàn)直到執(zhí)行到660多次之后才停下來(具體看機器配置),申請前80個線程的時間為10532毫秒,反正執(zhí)行的次數(shù)大大超出了限制的80次,回頭想想讓Timer不在激發(fā)事件的方法是調(diào)用timer.Dispose(),難不成是Dispose有延遲?延遲的過程中多執(zhí)行了500多次?那么我們再來做個試驗,我們在申請了80個線程后Timer剩余激發(fā)的線程選y,請耐心等待結(jié)果,在最后你會發(fā)現(xiàn)執(zhí)行時間還是660次左右,這很顯然是不合理的,如果Dispose有延遲時間造成所執(zhí)行500多次,那么加長80次后面每個線程的申請時間在相同的延遲時間內(nèi)申請的線程數(shù)應(yīng)該減少,因為后面500多個線程每個線程都要執(zhí)行1000毫秒,那么勢必有些線程會去申請新的線程有半秒鐘的等待時間(你會發(fā)現(xiàn)申請了80個線程后Timer剩余激發(fā)的線程選y明顯比選n慢得多,就是因為這個原因),所以看來不是因為Dispose造成的。

那么會是什么呢?我們這次這樣選在輸入是否執(zhí)行安全方法的時候選N,等待時間500,申請了80個線程后Timer剩余激發(fā)的線程選N

?

那么會是什么呢?我們這次這樣選在輸入是否執(zhí)行安全方法的時候選N,等待時間50,申請了80個線程后Timer剩余激發(fā)的線程選N

?

我們發(fā)現(xiàn)隨著每次任務(wù)等待時間的減少多執(zhí)行的次數(shù)也在減少,最關(guān)鍵的一點我們從圖中可以看到,前80次任務(wù)申請的時間也在減少,這是最關(guān)鍵的,根據(jù)上面線程池所講的內(nèi)容我們可以歸納出:每次任務(wù)的等待時間直接決定了前80個任務(wù)的執(zhí)行時間,因為等待時間越短,每個任務(wù)就可以越快執(zhí)行完,那么80個任務(wù)中就有越多的任務(wù)可以用到前面任務(wù)執(zhí)行完后釋放掉的線程,也就有越多的任務(wù)不必去線程池申請新的線程避免多等待半秒鐘的申請時間,而Timer并不會去關(guān)心線程池申請前80個任務(wù)的時間長短,只要它沒有執(zhí)行到timer.Dispose(),它就會每隔10毫秒激發(fā)一次響應(yīng)時間,不管前80次任務(wù)執(zhí)行時間是長還是短,timer都在第80次任務(wù)才執(zhí)行Dispose,執(zhí)行Dispose后timer就不會激發(fā)新的事件了,但是如果前80次任務(wù)申請的時間越長,那么timer就會在前80次任務(wù)申請的時間內(nèi)激發(fā)越多響應(yīng)事件,那么線程池中等待隊列中就會有越多的響應(yīng)函數(shù)等待申請線程,System.Threading.Timer沒有機制取消線程池等待隊列中多余的申請數(shù),所以導(dǎo)致等待時間越長,80次后執(zhí)行的任務(wù)數(shù)越多。

由此只用timer.Dispose()來終止Timer激發(fā)事件是不安全的,所以又寫了個安全的執(zhí)行機制:

class SafeTimer
{
??? static int i = 0;
??? static System.Threading.Timer timer;

??? static bool flag = true;
??? static object mylock = new object();

??? static void Excute(object obj)
??? {
??????? Thread.CurrentThread.IsBackground = false;

??????? lock (mylock)
??????? {
??????????? if (!flag)
??????????? {
??????????????? return;
??????????? }

??????????? i++;

??????????? if (i == 80)
??????????? {
??????????????? timer.Dispose();
??????????????? flag = false;
??????????? }
??????????? Console.WriteLine("Now:" + i.ToString());
??????? }

??????? Thread.Sleep(1000);//模擬花時間的代碼
??? }

??? public static void Init()
??? {
??????? timer = new System.Threading.Timer(Excute, null, 0, 10);
??? }
}

安全類中我們用了個bool類型的變量flag來判斷當前是否執(zhí)行到80次了,執(zhí)行到80次后將flag置為false,然后timer.Dispose,這時雖然任務(wù)還是要多執(zhí)行很多次但是由于flag為false,Excute函數(shù)一開始就做了判斷flag為false會立即退出,Excute函數(shù)80次后相當于就不執(zhí)行了。

3、System.Timers.Timer

在上面的例子中我們看到System.Threading.Timer很不安全,即使在安全的方法類,也只能讓事件響應(yīng)函數(shù)在80次后立刻退出讓其執(zhí)行時間近似于0,但是還是浪費了系統(tǒng)不少的資源。

所以本人更推薦使用現(xiàn)在介紹的System.Timers.Timer,System.Timers.Timer大致原理和System.Threading.Timer差不多,唯一幾處不同的就是:

?構(gòu)造函數(shù)不同,構(gòu)造函數(shù)可以什么事情也不做,也可以傳入響應(yīng)間隔時間:System.Timers.Timer timer = new System.Timers.Timer(10);
?響應(yīng)事件的響應(yīng)函數(shù)不在構(gòu)造函數(shù)中設(shè)置:timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
?聲明System.Timers.Timer對象后他不會自動執(zhí)行,需要調(diào)用 timer.Start()或者timer.Enabled = true來啟動它, timer.Start()的內(nèi)部原理還是設(shè)置timer.Enabled = true
?調(diào)用 timer.Stop()或者timer.Enabled = false來停止引發(fā)Elapsed事件, timer.Stop()的內(nèi)部原理還是設(shè)置timer.Enabled = false,最重要的是timer.Enabled = false后會取消線程池中當前等待隊列中剩余任務(wù)的執(zhí)行。
那么我們來看個例子:

view plaincopy to clipboardprint?
01.using System;??
02.using System.Collections.Generic;??
03.using System.Linq;??
04.using System.Text;??
05.using System.Timers;??
06.using System.Threading;??
07.?
08.namespace ConsoleApplication2??
09.{??
10.??? class UnSafeTimer??
11.??? {??
12.??????? static int i = 0;??
13.??????? static System.Timers.Timer timer;??
14.??????? static object mylock = new object();??
15.?
16.??????? public static void Init()??
17.??????? {??
18.??????????? timer = new System.Timers.Timer(10);??
19.??????????? timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);??
20.??????????? timer.Start();??
21.??????? }??
22.?
23.??????? static void timer_Elapsed(object sender, ElapsedEventArgs e)??
24.??????? {??
25.??????????? Thread.CurrentThread.IsBackground = false;??
26.??????????? int c;??
27.?
28.??????????? lock (mylock)??
29.??????????? {??
30.??????????????? i++;??
31.??????????????? c = i;??
32.??????????? }??
33.?
34.??????????? Console.WriteLine("Now:" + i.ToString());??
35.?
36.??????????? if (c == 80)??
37.??????????? {??
38.??????????????? timer.Stop();//可應(yīng)看到System.Timers.Timer的叫停機制比System.Threading.Timer好得多,就算在不安全的代碼下Timer也最多多執(zhí)行一兩次(我在試驗中發(fā)現(xiàn)有時會執(zhí)行到81或82),說明Stop方法在設(shè)置Timer的Enable為false后不僅讓Timer不再激發(fā)響應(yīng)事件,還取消了線程池等待隊列中等待獲得線程的任務(wù),至于那多執(zhí)行的一兩次任務(wù)我個人認為是Stop執(zhí)行過程中會耗費一段時間才將Timer的Enable設(shè)置為false,這段時間多余的一兩個任務(wù)就獲得了線程開始執(zhí)行??
39.??????????? }??
40.?
41.?
42.??????????? Thread.Sleep(1000);//等待1000毫秒模擬花時間的代碼,注意:這里的等待時間直接決定了80(由于是不安全模式有時會是81或82、83)個任務(wù)的執(zhí)行時間,因為等待時間越短,每個任務(wù)就可以越快執(zhí)行完,那么80個任務(wù)中就有越多的任務(wù)可以用到前面任務(wù)執(zhí)行完后釋放掉的線程,也就有越多的任務(wù)不必去線程池申請新的線程避免多等待半秒鐘的申請時間??
43.??????? }??
44.??? }??
45.?
46.??? class SafeTimer??
47.??? {??
48.??????? static int i = 0;??
49.??????? static System.Timers.Timer timer;??
50.?
51.??????? static bool flag = true;??
52.??????? static object mylock = new object();??
53.?
54.??????? public static void Init()??
55.??????? {??
56.??????????? timer = new System.Timers.Timer(10);??
57.??????????? timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);??
58.??????????? timer.Start();???
59.??????? }??
60.?
61.??????? static void timer_Elapsed(object sender, ElapsedEventArgs e)??
62.??????? {??
63.??????????? Thread.CurrentThread.IsBackground = false;??
64.?
65.??????????? lock (mylock)??
66.??????????? {??
67.??????????????? if (!flag)??
68.??????????????? {??
69.??????????????????? return;??
70.??????????????? }??
71.??????????????? i++;??
72.?
73.??????????????? Console.WriteLine("Now:" + i.ToString());??
74.?
75.??????????????? if (i == 80)??
76.??????????????? {??
77.??????????????????? timer.Stop();??
78.??????????????????? flag = false;??
79.??????????????? }??
80.??????????? }??
81.?
82.??????????? Thread.Sleep(1000);//同UnSafeTimer??
83.??????? }??
84.?
85.??????? class Program??
86.??????? {??
87.??????????? static void Main(string[] args)??
88.??????????? {??
89.??????????????? Console.Write("是否使用安全Timer>(Y/N)?");??
90.??????????????? string Key = Console.ReadLine();??
91.?
92.??????????????? if (Key.ToLower() == "y")??
93.??????????????????? SafeTimer.Init();??
94.??????????????? else?
95.??????????????????? UnSafeTimer.Init();??
96.?
97.??????????????? Console.ReadLine();??
98.??????????? }??
99.??????? }??
100.??? }??
101.}?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading;

namespace ConsoleApplication2
{
??? class UnSafeTimer
??? {
??????? static int i = 0;
??????? static System.Timers.Timer timer;
??????? static object mylock = new object();

??????? public static void Init()
??????? {
??????????? timer = new System.Timers.Timer(10);
??????????? timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
??????????? timer.Start();
??????? }

??????? static void timer_Elapsed(object sender, ElapsedEventArgs e)
??????? {
??????????? Thread.CurrentThread.IsBackground = false;
??????????? int c;

??????????? lock (mylock)
??????????? {
??????????????? i++;
??????????????? c = i;
??????????? }

??????????? Console.WriteLine("Now:" + i.ToString());

??????????? if (c == 80)
??????????? {
??????????????? timer.Stop();//可應(yīng)看到System.Timers.Timer的叫停機制比System.Threading.Timer好得多,就算在不安全的代碼下Timer也最多多執(zhí)行一兩次(我在試驗中發(fā)現(xiàn)有時會執(zhí)行到81或82),說明Stop方法在設(shè)置Timer的Enable為false后不僅讓Timer不再激發(fā)響應(yīng)事件,還取消了線程池等待隊列中等待獲得線程的任務(wù),至于那多執(zhí)行的一兩次任務(wù)我個人認為是Stop執(zhí)行過程中會耗費一段時間才將Timer的Enable設(shè)置為false,這段時間多余的一兩個任務(wù)就獲得了線程開始執(zhí)行
??????????? }


??????????? Thread.Sleep(1000);//等待1000毫秒模擬花時間的代碼,注意:這里的等待時間直接決定了80(由于是不安全模式有時會是81或82、83)個任務(wù)的執(zhí)行時間,因為等待時間越短,每個任務(wù)就可以越快執(zhí)行完,那么80個任務(wù)中就有越多的任務(wù)可以用到前面任務(wù)執(zhí)行完后釋放掉的線程,也就有越多的任務(wù)不必去線程池申請新的線程避免多等待半秒鐘的申請時間
??????? }
??? }

??? class SafeTimer
??? {
??????? static int i = 0;
??????? static System.Timers.Timer timer;

??????? static bool flag = true;
??????? static object mylock = new object();

??????? public static void Init()
??????? {
??????????? timer = new System.Timers.Timer(10);
??????????? timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
??????????? timer.Start();
??????? }

??????? static void timer_Elapsed(object sender, ElapsedEventArgs e)
??????? {
??????????? Thread.CurrentThread.IsBackground = false;

??????????? lock (mylock)
??????????? {
??????????????? if (!flag)
??????????????? {
??????????????????? return;
??????????????? }
??????????????? i++;

??????????????? Console.WriteLine("Now:" + i.ToString());

??????????????? if (i == 80)
??????????????? {
??????????????????? timer.Stop();
??????????????????? flag = false;
??????????????? }
??????????? }

??????????? Thread.Sleep(1000);//同UnSafeTimer
??????? }

??????? class Program
??????? {
??????????? static void Main(string[] args)
??????????? {
??????????????? Console.Write("是否使用安全Timer>(Y/N)?");
??????????????? string Key = Console.ReadLine();

??????????????? if (Key.ToLower() == "y")
??????????????????? SafeTimer.Init();
??????????????? else
??????????????????? UnSafeTimer.Init();

??????????????? Console.ReadLine();
??????????? }
??????? }
??? }
}

?這個例子和System.Threading.Timer差不多,這里也分為:安全類SafeTimer和不安全類UnSafeTimer,原因是 timer.Stop()有少許的延遲時間有時任務(wù)會執(zhí)行到81~83,但是就算是不安全方法也就最多多執(zhí)行幾次,不像System.Threading.Timer多執(zhí)行上百次...

所以我這里還是推薦大家使用System.Timers.Timer

?

本文來自CSDN博客,轉(zhuǎn)載請標明出處:http://blog.csdn.net/BusyDonkey/archive/2010/02/25/5327665.aspx

?

轉(zhuǎn)載于:https://www.cnblogs.com/Godblessyou/archive/2011/04/28/2031884.html

總結(jié)

以上是生活随笔為你收集整理的C#的Timer解析(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。