.NET中有多少種定時器

.NET中至少有6種定時器,每一種定時器都有它的用途和特點。根據定時器的應用場景,可以分為UI相關的定時器和UI無關的定時器。本文將簡單介紹這6種定時器的基本用法和特點。

UI定時器

.NET中的UI定時器主要是WinForm、WPF以及WebForm中的定時器。分別為:

  • System.Windows.Forms.Timer

  • System.Windows.Threading.DispatcherTimer

  • System.Web.UI.Timer

通常情況下,WinForm、WPF中的定時器是在UI線程上執行回調函數,因此可以直接訪問UI元素。由于WinForm、WPF支持單線程單元模型(Single-Thread Apartment,STA),定時器間隔事件是在UI線程上觸發,因此,不用擔心線程安全問題。System.Web.UI.Timer是通過Javascript定時器和服務端異步回調實現,也是單線程的。

請注意,這里說的是通常情況,后邊介紹System.Windows.Threading.DispatcherTimer時會提到在非UI線程創建DispatcherTimer時也無法直接訪問UI元素。

System.Windows.Forms.Timer

System.Windows.Forms.Timer針對WinForm應用進行了優化,是只能在WinForm上使用的定時器。這個定時器是針對單線程環境設計的,是在UI線程上處理定時任務。它要求用戶代碼有可用的UI消息泵,定時任務須在UI線程上運行,或者跨線程通過Invoke或者BeginInvoke封送(marshal)到UI線程上運行。其優點是使用簡單,只需通過給Interval屬性賦值來設置時間間隔,并注冊Tick事件處理定時任務。其缺點是精度不高,精度為55毫秒,也就是Interval賦值小于55時,也是55毫秒觸發一次定時任務。

public partial class TimerFrom : Form
{private System.Windows.Forms.Timer digitalClock;private void TimerFrom_Load(object sender, EventArgs e){digitalClock = new System.Windows.Forms.Timer();//創建定時器 digitalClock.Tick += new EventHandler(HandleTime);//注冊定時任務事件 digitalClock.Interval = 1000;//設置時間間隔digitalClock.Enabled = true;digitalClock.Start(); //開啟定時器}public void HandleTime(Object myObject, EventArgs myEventArgs){labelClock.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");}private void frmTimerDemo_FormClosed(object sender, FormClosedEventArgs e){digitalClock.Stop();//停止定時器digitalClock.Dispose();}
}

System.Windows.Threading.DispatcherTimer

System.Windows.Threading.DispatcherTimer是WPF中的定時器,它是基于Dispatcher對象的(并不是基于UI線程的)。DispatcherTimer的定時任務是像其他操作一樣放在Dispatcher隊列上,其執行操作時間依賴于隊列中其他任務及其優先級,因此,DispatcherTimer不保證在時間間隔發生時準確執行,只保證不會在時間間隔發生前執行。

Dispatcher為特定線程維護工作項(操作)的優先級隊列,在線程上創建Dispatcher對象時,它成為唯一可以關聯該線程的Dispatcher對象,WPF中,DispatcherObject只能被與之關聯的Dispatcher對象訪問,也就是非UI線程中無法直接訪問UI元素(WPF中的UI元素都是派生自DispatcherObject

此外,DispatcherTimer不像System.Windows.Forms.Timer那樣只在UI線程上創建才能觸發Tick事件,它在非UI線程下創建也可以觸發Tick事件,此時訪問UI元素也需要通過Invoke或者BeginInvoke封送(marshal)到UI線程上運行。其優點也是簡單易用,適合在UI線程上執行任務或觸發事件,缺點是精度不準確,可能存在延遲。

private void Dt_Tick(object sender, EventArgs e)
{Dispatcher.BeginInvoke((Action)delegate (){text1.Text = DateTime.Now.ToString();});Console.WriteLine(DateTime.Now.ToString());
}private void Button_Click(object sender, RoutedEventArgs e)
{Task.Run(() =>{DispatcherTimer dt = new DispatcherTimer();dt.Tick += Dt_Tick;dt.Interval = TimeSpan.FromSeconds(1);dt.Start();Dispatcher.Run();});
}

上述代碼中,DispatcherTimer是非UI線程中創建,定時任務中訪問UI元素text1,需要通過Invoke或者BeginInvoke封送(marshal)到UI線程上運行,而Console.WriteLine則可以直接運行。

System.Web.UI.Timer

System.Web.UI.Timer是僅適用于.NET FrameworkASP.NET組件。通過Javascript定時器和服務端異步回調實現。每次觸發定時器時,只能執行一個異步回調方法,而其他的異步回調方法需要等待前一個異步回調方法執行完畢后才能執行。這樣可以保證在任意時刻只有一個異步回調方法在執行,避免了多線程并發執行的問題。

UI無關定時器

從 .NET 6開始,UI無關定時器有三個:

  • System.Threading.Timer

  • System.Timers.Timer

  • System.Threading.PeriodicTimer(.NET 6+)

System.Threading.Timer

System.Threading.Timer是最基礎輕量的定時器,它將定期在線程池線程上執行單個回調方法。在創建定時器對象時必須指定回調方法,并且后續不能修改,同時也可以指定定時器回調開始執行的時間以及時間間隔。定時器創建后可以通過Change方法修改回調開始執行的時間以及時間間隔。該定時器的優點是輕量,精度相對較高,與Windows操作系統時鐘精度一致,大約15毫秒。但因為是基于線程池的,所以在任務執行時間較長或者線程池過載時,會出現延遲。其缺點是使用不太方便,定時器創建后無法修改回調方法。

var stateTimer = new 
var autoEvent = new AutoResetEvent(false);
Timer(CheckStatus, autoEvent, 1000,250);private int invokeCount=0;public void CheckStatus(Object stateInfo)
{AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;Console.WriteLine("{0} Checking status {1,2}.",DateTime.Now.ToString("h:mm:ss.fff"),(++invokeCount).ToString());if(invokeCount == 10){invokeCount = 0;autoEvent.Set();}
}

System.Timers.Timer

System.Timers.Timer在內部使用System.Threading.Timer,并公開了更多的屬性,如AutoReset,?EnabledSynchronizingObject,這些屬性允許配置回調的執行方式。此外,Tick事件允許注冊多個處理程序。因此,一個定時器可以觸發多個處理程序。還可以在計時器啟動后更改處理程序。與System.Threading.Timer相似,其優點也是精度相對較高,與Windows操作系統時鐘精度一致,大約15毫秒。因為默認(或者SynchronizingObject=null時)是基于線程池的,所以在任務執行時間較長或者線程池過載時,會出現延遲。但使用要更簡便一些。

public partial class TimerFrom : Form
{private System.Timers.Timer timer;private void TimerFrom_Load(object sender, EventArgs e){// 支持注冊多個處理程序timer.Elapsed += (sender, e) => { label1.Text = DateTime.Now.ToLongTimeString(); };timer.Elapsed += (sender, e) => { Console.WriteLine(DateTime.Now.ToLongTimeString()); };//自定義回調執行的方式(指定對象所在的線程),SynchronizingObject=null時在線程池上執行timer.SynchronizingObject = this;timer.AutoReset = true;timer.Start();}
}

本例中將SynchronizingObject屬性設置為Form對象,因此Elapsed的處理程序在UI線程上執行,可以直接修改label1.Text,如果SynchronizingObject屬性為null,處理程序則是在線程池線程上執行,修改label1.Text時需要通過Invoke或者BeginInvoke封送(marshal)到UI線程上運行。

System.Threading.PeriodicTimer

System.Threading.PeriodicTimer是 .NET 6中引入的定時器。它能方便地使用異步方式,它沒有Tick事件,而是提供WaitForNextTickAsync方法處理定時任務。通常是使用While循環結合CancellationToken一起使用。和CancellationToken一起用的時候需要注意,如果CancellationToken被取消的時候會拋出一個OperationCanceledException需要考慮自己處理異常。相比之前的定時器來說,有下面幾個特點:[1]

  1. 沒有callback?來綁定事件;

  1. 不會發生重入,只允許有一個消費者,不允許同一個PeriodicTimer在不同的地方同時WaitForNextTickAsync,不需要自己做排他鎖來實現不能重入;

  1. 異步化。之前的 timer 的 callback 都是同步的,使用新 timer 可以使用異步方法,避免了編寫 Sync over Async 代碼;

  1. Dispose 之后,實例就無法使用,并且 WaitForNextTickAsync 始終返回 false。

var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
using (var timer = new PeriodicTimer(TimeSpan.FromSeconds(1)))
{try{while (await timer.WaitForNextTickAsync(cts.Token)){await Task.Delay(3000);Console.WriteLine($"ThreadId is {Thread.CurrentThread.ManagedThreadId} --- Time is {DateTime.Now:HH:mm:ss}");}}catch (OperationCanceledException){Console.WriteLine("Operation cancelled");}
}

小結

我們在開發過程中遇到的坑往往不是技術本身的坑,而是我們濫用沒有掌握的技術導致的,在有多種技術方案可選的時候,通常只關注技術的優點,忽略了技術適用場景及其局限性。.NET中幾種定時器各自都有其適用場景和不足,但都不支持高精度計時。了解這些有助于我們在開發過程中選擇合適定時器,避免遇到問題后被動地替換解決方案。

文章轉載自:czwy

原文鏈接:https://www.cnblogs.com/czwy/p/17862702.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/207158.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/207158.shtml
英文地址,請注明出處:http://en.pswp.cn/news/207158.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

dell服務器重啟后顯示器黑屏

1.硬件層面:觀察主機的指示燈 (1)指示燈偏黃,硬件存在問題(內存條有靜電,拔出后用橡皮擦擦拭;或GPU松動) a.電源指示燈黃,閃爍三下再閃爍一下,扣下主板上的紐…

Python Appium Selenium 查殺進程的實用方法

一、前置說明 在自動化過程中,經常需要在命令行中執行一些操作,比如啟動應用、查殺應用等,因此可以封裝成一個CommandExecutor來專門處理這些事情。 二、操作步驟 # cmd_util.pyimport logging import os import platform import shutil i…

Java編程中通用的正則表達式(二)

正則表達式,又稱正則式、規則表達式、正規表達式、正則模式或簡稱正則,是一種用來匹配字符串的工具。它是一種字符串模式的表示方法,可以用來檢索、替換和驗證文本。正則表達式是一個字符串,它描述了一些字符的組合,這…

dockers安裝rabbitmq

RabbitMQ: easy to use, flexible messaging and streaming — RabbitMQhttps://www.rabbitmq.com/ Downloading and Installing RabbitMQ — RabbitMQ docker run -it --rm --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.12-management 之后參照:dock…

高低壓配電智能監控系統

高低壓配電智能監控系統是一種綜合運用物聯網、云計算、大數據和人工智能等技術的智能化監控系統,主要用于對高低壓配電設備進行實時監測、數據采集、故障預警和遠程管理。 該系統通過安裝智能傳感器、智能設備、網絡通訊技術等手段,依托電易云-智慧電力…

解決“由于找不到msvcr110.dll無法繼續執行”的錯誤問題,一鍵修復msvcr110.dll丟失

當你遇到“由于找不到msvcr110.dll無法繼續執行”的錯誤時,通常是因為你的電腦缺少相關的msvcr110.dll文件。如果你的電腦中缺失了msvcr110.dll文件丟失那么可以根據下面的方法嘗試解決msvcr110.dll丟失的問題。 一.解決msvcr110.dll丟失的方法 使用dll修復工具 D…

設計圖中時序圖

設計圖中的時序圖通常用于展示兩個或多個對象之間的交互和消息傳遞的順序。它是一種用于描述軟件或系統中的并發性和時序行為的工具。 以下是一個簡單的時序圖的示例: 首先,在時序圖中創建兩個對象,例如"對象A"和"對象B&quo…

學習筆記9——JUC三種量級的鎖機制

學習筆記系列開頭慣例發布一些尋親消息 鏈接:https://baobeihuijia.com/bbhj/contents/3/197325.html 多線程訪問共享資源沖突 臨界區:一段代碼塊存在對共享資源的多線程讀寫操作,稱這段代碼塊為臨界區 競態條件:多個線程在臨界…

Linux OpenMP使用總結

當涉及到編寫 Linux OpenMP 程序時,以下是體會: 了解 OpenMP 基礎:在使用 OpenMP 進行并行編程之前,確保您了解并行編程的基本概念和 OpenMP 的工作原理。您可以參考 OpenMP 的官方文檔或其他相關資源來獲取更多信息。配置 OpenM…

#HarmonyOS:@Styles裝飾器:定義組件重用樣式

Styles可以定義在組件內或全局,在全局定義時需在方法名前面添加function關鍵字,組件內定義時則不需要添加function關鍵字。 組件內Styles的優先級高于全局Styles。 框架優先找當前組件內的Styles,如果找不到,則會全局查找。 // …

GO設計模式——3、抽象工廠模式(創建型)

目錄 抽象工廠模式(Abstract Factory Pattern) 抽象工廠模式的核心角色 優缺點 代碼實現 抽象工廠模式(Abstract Factory Pattern) 抽象工廠模式(Abstract Factory Pattern)是圍繞一個超級工廠創建其他…

單詞倒排

對字符串中的所有單詞進行倒排。 說明: 1、構成單詞的字符只有26個大寫或小寫英文字母; 2、非構成單詞的字符均視為單詞間隔符; 3、要求倒排后的單詞間隔符以一個空格表示;如果原字符串中相鄰單詞間有多個間隔符時,倒排…

yolo目標檢測+目標跟蹤+車輛計數+車輛分割+車道線變更檢測+速度估計

這個項目使用YOLO進行車輛檢測,使用SORT(簡單在線實時跟蹤器)進行車輛跟蹤。該項目實現了以下任務: 車輛計數車道分割車道變更檢測速度估計將所有這些詳細信息轉儲到CSV文件中 車輛計數是指在道路上安裝相應設備,通過…

windows下 Tomcat啟動黑框隱藏

進入到 tomcat/bin 目錄下,找到此文件 setclasspath.bat ,右鍵文本打開 找到此屬性 : set _RUNJAVA"%JRE_HOME%\bin\java.exe"修改成以下屬性,保存文件,重啟啟動tomcat會發現黑框不默認彈出了: …

使用hutool工具生成非對稱加密公私密鑰以及使用案例

1.導入hutool依賴 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.18</version></dependency>2.直接復制代碼 package com.common.utils;import cn.hutool.core.codec.Base64; i…

僅需30秒完美復刻任何人的聲音 - 最強AI音頻11Labs

我的用詞一直都挺克制的&#xff0c;基本不會用到“最強”這個字眼。 但是這一次的這個AI應用&#xff0c;是我認為在TTS&#xff08;文字轉音頻&#xff09;這個領域&#xff0c;當之無愧的“最強”。 ElevenLabs&#xff0c;簡稱11Labs。 僅需30秒到5分鐘左右的極少的數據集…

機器學習-分類問題

前言 《機器學習-回歸問題》知道了回歸問題的處理方式,分類問題才是機器學習的重點.從數據角度講,回歸問題可以轉換為分類問題的微分 邏輯回歸 邏輯回歸&#xff08;Logistics Regression&#xff09;,邏輯回歸雖然帶有回歸字樣&#xff0c;但是邏輯回歸屬于分類算法。但只可…

極大提升GPT-4等模型推理效率,微軟、清華開源全新框架

隨著用戶需求的增多&#xff0c;GPT-4、Claude等模型在文本生成、理解、總結等方面的能力越來越優秀。但推理的效率并不高&#xff0c;因為&#xff0c;多數主流模型采用的是“順序生成詞”方法&#xff0c;會導致GPU利用率很低并帶來高延遲。 為了解決這一難題&#xff0c;清…

美國Linux服務器的iptables防火墻介紹

美國Linux服務器防火墻一般分為硬件防火墻和軟件防火墻&#xff0c;但不論是硬件防火墻還是軟件防火墻&#xff0c;都需要通過使用硬件作為聯機的介質&#xff0c;也需要使用軟件來設定美國Linux服務器安全政策&#xff0c;因此可以從使用的硬件與操作系統來加以區分。硬件防火…

oracle怎么推進scn?

很多時候&#xff0c;數據庫有故障打不開&#xff0c;需要用到推進scn的技術&#xff0c;這里介紹下12c及以上版本的oracle怎么推進數據庫的scn。 經測試發現&#xff0c;數據庫mount和open狀態下都可以通過此方法推進SCN。 Session1&#xff1a; 查詢當前SCN SQL> select c…