c#: 四種定時器

環境:

  • window 10
  • vs2016 16.5.1
  • .netcore 3.1.1

實驗目的:
實驗c#中的多線程定時器和單線程定時器

參照: 深入淺出多線程系列之七:4種定時器

在Framework中存在着4種定時器:其中分爲兩類:多線程計時器和特殊目的的單線程計時器。多線程計時器比較強大,精確,而且可擴展性強;單線程計時器比較安全,對於更新 Windows Forms controls或者WPF這種簡單任務來說更方便。

一、多線程計時器

1.1 System.Threading.Timer

參照官方文檔:Timer 類
System.Threading.Timer是最簡單的多線程計時器,由線程池線程服務,簡單且對資源要求不高。在下面的例子中,定時器在5秒後開始定時1秒的調用Tick方法。

using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Threading;
namespace TestDI
{
    class Program
    {
        public static void Main(string[] args)
        {
            System.Threading.Timer timer = new Timer((state) =>
            {
                state += $"任務線程:{Thread.CurrentThread.ManagedThreadId} " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " isThreadPool:" + Thread.CurrentThread.IsThreadPoolThread;
                Console.WriteLine(state);
            }, "hello", 5000, 1000);

            Console.WriteLine($"主線程:{Thread.CurrentThread.ManagedThreadId}");
            Console.ReadLine();
        }
    }
}

輸出效果:
在這裏插入圖片描述
可以看出,確實是多線程執行!

注意:只要您使用 Timer,就必須保留對它的引用。 與任何託管對象一樣,當不存在任何引用時,Timer 可能會進行垃圾回收。 即使 Timer 仍處於活動狀態,也不會阻止收集它。

1.2 System.Timers.Timer

.net framework提供的另一個計時器System.Timers.Timer.簡單的對System.Threading.Timer進行了包裝,增加了下面幾個特性:

  • 實現了Component,所以可以在設計器顯示。
  • 代替Change方法的一個Interval屬性
  • 代替callback委託的一個Elapsed事件
  • 增加Start/Stop方法控制開啓和停止

直接看使用示例:

using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Threading;
namespace TestDI
{
    class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine($"主線程:{Thread.CurrentThread.ManagedThreadId}");
            System.Timers.Timer timer = new System.Timers.Timer()
            {
                Interval = 1000,
                Enabled = false
            };
            timer.Elapsed += (state, e) =>
                {
                    Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}, 任務線程:{Thread.CurrentThread.ManagedThreadId},IsThreadPoolThread:{Thread.CurrentThread.IsThreadPoolThread},state={state}");
                };
            Console.WriteLine("等待主線程開啓定時器!");
            Thread.Sleep(2000);
            timer.Start();
            Console.WriteLine("主線程已開啓定時器!");
            Thread.Sleep(10 * 1000);
            timer.Stop();
            Console.WriteLine("主線程已關閉定時器!");
            Console.ReadLine();
        }
    }
}

輸出效果:
在這裏插入圖片描述

二、單線程計時器

單線程計時器是被設計成屬於他們執行環境的計時器,如果你在一個Windows服務應用程序中使用Windows Forms的Timer,timer 事件並不會被觸發,只有在對應的環境下才會被觸發。
像System.Timers.Timer一樣,他們也提供了相同的成員(Interval,Tick,Start,Stop),但是他們內部的工作原理不同,WPF和Windows Forms的計時器使用消息循環機制來取代線程池產生消息的機制。這意味着Tick事件總是在創建timer的那個線程上執行,同時也意味着如果上一個Tick消息還未被處理,即使時間超過了間隔時間,在消息循環中也只存在一個Tick消息。
下面是它們的優點:

  • 你可以忘記線程安全。
  • 一個Tick事件在前一個Tick事件被處理完畢前不會被觸發。
  • 你可以直接在Tick事件處理代碼中更新控件,不需要調用Control.Invoke或Dispatcher.Invoke。

缺點:

  • 由於單線程執行,所以除非Tick事件的處理代碼執行的非常快,否則UI界面會變得響應很慢。

所以 WPF和Windows Forms的計時器都非常適合小任務,尤其是界面更新的任務。例如時鐘和計數顯示。否則,你需要一個多線程計時器。

2.1 System.Windows.Forms.Timer(Windows Forms Timer)

winform中最常用,不再演示。

2.2 System.Windows.Threading.DispatcherTimer(WPF timer)

用在wpf中。。。

參考資料:

http://www.albahari.com/threading/

CLR Via C# 3.0

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章