超耗時迴圈暫停/繼續功能(二)
話說前一個範例還不夠完美,因為執行完程式後並沒有做資源回收的工作,也就是說,並沒有加上刪除中斷時為了記錄執行進度用的進度檔。
前篇範例簡單的流程圖請參閱底下的圖一,有助於大家對流程的熟悉與了解。

當然,程式碼還能額外增加一些防呆功能,好比說整個需要演算的東西都已經處理完畢結束,就不必重新再跑一次,尤其是萬一不小心再執行到,那麼又要再花時間耗時了,做做這樣子的防呆也是必要的,除非想再驗證一下演算是否錯誤,那麼也得讓程式聰明點,至少別把已經處理好的輸出檔案給刪掉,得小心手誤而做了超級大白工。
除了前一篇文章提到的自動存檔,這裡可分成兩個方向來研究,一種是計時、另一種是計量。
差別差在哪兒呢?講起來也有點複雜,在固定的執行時間裡保存一次,這方法得配合計時器或是時鐘來應用,時間檢查可能會多了點;固定執行次數的方法相對就簡單了些,只要執行次數符合等差數列就保存一次,缺點就很明顯,每執行一次耗時多久就成了頭痛問題,公差的大小多少都會影響到執行效能。
不管用哪種,總需要在迴圈裡放個 DoEvents 指令讓系統來處理一下各種視窗的事件,但也曾經提過,過份使用 DoEvents 指令也會造成迴圈執行效能低落,請參閱:別濫用 DoEvents 函數、別濫用 DoEvents 函數(二)。
改良版本的可自動儲存、中斷/恢復範例:- ' 請把上一章節 Command1_Click() 內容中呼叫「耗時1」改為「耗時2」
- ' 改寫「耗時1」後的原始碼
- Sub 耗時2()
- Dim i As Long, j As Long
- Dim Count As Long
- Dim FileNum As Integer, FileNum2 As Integer
- Dim 檔名 As String, 進度檔 As String
- Dim 迴圈上限 As Long
- 迴圈上限 = 10000000
- 進度檔 = RunPath & "進度.set"
- 檔名 = RunPath & "TestFile1.txt"
- FileNum = FreeFile
- ' 檢查檔案是否存在
- If Len(Dir(進度檔, vbArchive Or vbHidden Or vbNormal Or vbReadOnly)) = 0 Then
- If Len(Dir(檔名, vbArchive Or vbHidden Or vbNormal Or vbReadOnly)) <> 0 Then
- If MsgBox(檔名 & vbCrLf & "己存在,是否覆寫?", 305, "警告") = vbCancel Then Exit Sub
- End If
- ' 重設起始位置
- regType.i = 0
- regType.Count = 0
-
- Open 檔名 For Output As FileNum ' 重設資料檔
- Else
- ' 取得最後中斷位置
- Open 進度檔 For Binary As FileNum
- Get #FileNum, , regType
- Close #FileNum
-
- Open 檔名 For Append As FileNum ' 追加資料
- End If
- Count = regType.Count
- For i = regType.i To 迴圈上限
- If i Mod 100 = 0 Then
- DoEvents ' 取得中斷狀態
- If 中斷旗號 Then
- ' 記錄執行狀態與結果
- regType.i = i
- regType.Count = Count
-
- FileNum2 = FreeFile
- Open 進度檔 For Binary As FileNum2
- Put #FileNum2, , regType
- Close #FileNum2
- Exit For ' 強制結束迴圈
- End If
- End If
-
- ' 處理耗時迴圈內的演算內容...
- If i Mod 2 = 0 Then
- Count = Count + i
- Else
- Count = Count - i
- End If
-
- Print #FileNum, Count ' 資料輸出
- Next
- Close #FileNum
- If i > 迴圈上限 Then
- ' 執行完成, 回收進度設定
- If Len(Dir(進度檔, vbArchive Or vbHidden Or vbNormal Or vbReadOnly)) = 0 Then Kill 進度檔
- End If
- End Sub
複製代碼 強化後的流程圖:

結論:
嚴格上來講本篇是只換湯不換藥的應用,可以追加的功能也許不少,全憑使用上的需求。我個人不太喜歡執行起來令表單有顯示反應呆滯狀況的程式,更不喜歡不能自由決定何時能暫停休息一下的程式,才會有這一大堆又臭又長怪模怪樣的方法來解決問題。
我個人能忍受表單毫無反應的時間是十秒至三十秒左右,超過了便會懷疑程式已經死當了,事實上也許未必是這種狀況,總不能讓使用者無法得知執行的進度吧?強迫使用者陪程式浪費時間玩猜謎是件很不道德的事,請盡量避免比較好。
嗯,還有多層迴圈如何中斷的題材可以研究。
本文同步刊載於:http://tw.myblog.yahoo.com/shege-1975/article?mid=2283 |