[VB6][VBA][VB.net] 再談 Timer 控制項 - 時間解析度過低的解決方法(二)用 Do…Loop 模擬 Timer
- 前文說到 VB6 提升 Timer 解析度的方法在 VB.net 可以用 Stopwatch 解決。
- 現在就來實作一個測試程式來觀察比較一下。
- 環境 OS 是 Windows7 x64,CPU 2.6GHz。
-
程式使用三種計時的基準:
- 使用 System.Windows.Forms.Timer 類別(原來工具箱的控制項)
- 使用 Microsoft.VisualBasic.DateAndTime.Timer() 函數
- 使用 System.Diagnostics.Stopwatch 類別
-
結果如下:
- 計時 0.5 秒, Interval = 1ms(Count 應為 499) 時只有 Stopwatch 接近正常,Timer Control 清楚的表明在半秒之內只做 32 次(前文所說的 1/64)。
- 計時 0.5 秒, Interval = 2ms(Count 應為 249) 時只有 Stopwatch 和 Timer() 函數正常。Timer Control 仍堅持只做 32 次(0.5*64 = 32)
-
計時 1.0 秒, Interval = 2ms(Count 應為 499) 時只有 Stopwatch 和 Timer() 函數正常。Timer Control 做了 64次(1*64 = 64)
1 2 3
-
再看其他條件下的表現:
- 計時 0.005 秒,Interval = 1ms(Count 應為 4) 時只有 Stopwatch 最正確,Timer() 函數因為 Time up 時間點不夠精準多算了一次。
- 計時 0.1 秒,Interval = 5ms(Count 應為 19) 時只有 Stopwatch 最正確,Timer() 函數仍多算了一次,Timer Control 六次(0.1*64 = 6.4)。
-
計時 2 秒,Interval = 20ms(Count 應為 99) 時只有 Stopwatch 最正確,Timer() 函數仍多算了一次,Timer Control 做 64 次(Interval 太小所致)。
1 2 3
- 看完以上測試結果,會不會覺得做成獨立的控制項,再封裝成 dll 會更方便呢?下回再貼囉。
-
原始碼如下:
Imports System.Diagnostics Imports Microsoft.VisualBasic Imports System.Text Public Class Form1 Dim 計時元件 As New Stopwatch Dim 時訊週期 As Long = Stopwatch.Frequency Dim 經過時間 As Single = 0 Dim 總計時秒數 As Double Dim 事件週期 As Double Dim 事件觸發次數 As Long = 0 Dim 結果列表 As New List(Of String) Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load cbx_測試秒數.SelectedIndex = 5 cbx_事件週期.SelectedIndex = 4 Text = "Timer 精確度測試" 計時元件.Reset() cbx_Change() End Sub Private Sub cbx_Change() Handles cbx_測試秒數.SelectedIndexChanged, cbx_事件週期.SelectedIndexChanged Try If cbx_測試秒數.Text <> "" Then 總計時秒數 = (cbx_測試秒數.Text) If cbx_事件週期.Text <> "" Then 事件週期 = (cbx_事件週期.Text) lbl_CPU_clock.Text = "CPU Clock = " & Format(時訊週期 * 1024 / 1000000000, "###.### GHz") lbl_描述.Text = "在 " & 總計時秒數 & "s 內每隔 " & 事件週期 * 1000 & "ms 觸發一次事件。" Catch ex As Exception End Try End Sub Sub 重建測試條件() 事件觸發次數 = 0 經過時間 = 0 結果列表.Clear() lst_顯示結果.Items.Clear() End Sub Sub 顯示結果(ByVal btn As Button) lst_顯示結果.ForeColor = btn.ForeColor For Each i In 結果列表 lst_顯示結果.Items.Add(i) Next End Sub Private Sub B1() Handles btn_Timer控制項.Click 重建測試條件() Dim 測試開始時間 As Long = 0 Dim 階段計時起點 As Double = 0 Dim 比對次數 As Long = 0 計時元件.Start() 測試開始時間 = 計時元件.ElapsedTicks 階段計時起點 = 計時元件.ElapsedTicks Timer1.Interval = 事件週期 * 1000 Timer1.Enabled = True Do Application.DoEvents() Loop While (計時元件.ElapsedTicks - 測試開始時間) / 時訊週期 < 總計時秒數 Timer1.Enabled = False 顯示結果(btn_Timer控制項) End Sub Private Sub B2() Handles btn_Timer函式.Click 重建測試條件() Dim 測試開始時間 As Long = 0 Dim 階段計時起點 As Double = 0 Dim 比對次數 As Long = 0 計時元件.Start() 測試開始時間 = 計時元件.ElapsedTicks 階段計時起點 = Microsoft.VisualBasic.Timer Do 比對次數 += 1 '---用 Timer() 函數值判判是否執行計時器事件---- 經過時間 = Microsoft.VisualBasic.Timer - 階段計時起點 If (Microsoft.VisualBasic.Timer - 階段計時起點) > 事件週期 Then 階段計時起點 = Microsoft.VisualBasic.Timer 事件觸發次數 += 1 '-----計時器事件放在這裡-------------------------------------------------------------- 結果列表.Insert(0, "第 " & 事件觸發次數 & " 次事件" & vbTab & 比對次數 & vbTab & 經過時間 & " 秒") '------------------------------------------------------------------------------------- 比對次數 = 0 End If Application.DoEvents() Loop While (計時元件.ElapsedTicks - 測試開始時間) / 時訊週期 < 總計時秒數 顯示結果(btn_Timer函式) End Sub Private Sub B3() Handles btn_StopWatch.Click 重建測試條件() Dim 測試開始時間 As Long = 0 Dim 階段計時起點 As Long = 0 Dim 比對次數 As Long = 0 計時元件.Restart() 測試開始時間 = 計時元件.ElapsedTicks 階段計時起點 = 計時元件.ElapsedTicks Do 比對次數 += 1 '---用 Ticks Count 判判是否執行計時器事件---- 經過時間 = (計時元件.ElapsedTicks - 階段計時起點) / 時訊週期 If 經過時間 > (事件週期) Then 階段計時起點 = 計時元件.ElapsedTicks 事件觸發次數 += 1 '-----計時器事件放在這裡-------------------------------------------------------------- 結果列表.Insert(0, "第 " & 事件觸發次數 & " 次事件" & vbTab & 比對次數 & vbTab & 經過時間 & " 秒") '------------------------------------------------------------------------------------- 比對次數 = 0 End If Application.DoEvents() Loop While (計時元件.ElapsedTicks - 測試開始時間) / 時訊週期 < 總計時秒數 顯示結果(btn_StopWatch) End Sub Private Sub T1() Handles Timer1.Tick Static 階段計時起點 As Long = 0 事件觸發次數 += 1 經過時間 = (計時元件.ElapsedTicks - 階段計時起點) / 時訊週期 結果列表.Insert(0, "第 " & 事件觸發次數 & " 次事件" & vbTab & "idle" & vbTab & 經過時間 & " 秒") 階段計時起點 = 計時元件.ElapsedTicks End Sub End Class
專案包下載 timer_demo.rar