VB6/VBNET CPU 資源釋出

我以為我已經寫過這個主題了說… 結果居然找沒有。

在各 Windows 程式下其實都有這個需求,這邊只討論 VB 。
這個資源釋出,通常在大量的長時間回圈計算或等待時,特別需要。使用的時機主要可分成需要精準計時或是可有誤差的計時。
Windows 是多程序、多緒的程式,若某個執行緒霸占著 CPU 不放出來,在 Win9x 是採用非強制多工,所以會導致整個系統停止回應,在 WinNT (NT/2k/XP/2003/Vista) 是採用強制多工,所以會導致系統雖然仍然能跑,但是反應較緩慢,此外,CPU 也處於滿載運作中。
超緒或多核心由於會保留 1 個 CPU 來執行作業系統,所以可能 CPU 負載為 50% 而非 100% (指兩顆 CPU 的狀態)。
VB為了減少使用者的困擾,所以 VB 提供了 DoEvents/Application.DoEvents 來讓 CPU 暫時讓出執行其他程式,或是其他狀態更新,但是即使使用了這個指令,CPU 使用率並不會降低,而仍然處於滿載,若要減緩這個狀況,且不在一些微的時間損失時,可在 DoEvents 完後,呼叫 API Sleep/System.Threading.Thread.Sleep 。
那麼呼叫 Sleep 時要睡多久呢?這看你的需求,一般來說是 0 ~ 500 ms 。
若你的程式要減少最小損耗時,可以睡 0 ms ,這樣並不能降低 CPU 使用率很多,若在 ASP.NET 下,則只有這種方法來放出 CPU 資源,而解決沒有 Application.DoEvents 的困擾。
我建議預設是睡 1 ms,當你睡超過 0 ms 時,CPU 才會真的被釋放出來,睡眠的間距受 GetTickCount 影響解析度,目前在 WinNT 上為 10 ms,在 Win9x 上為 54 ms,換句話說,在 WinNT 上即使睡 1 ms,也會睡到下個 10 ms 間隔,也就是說有可能睡 1 ~ 10 ms ,這樣可以確保執行緒睡眠時間最短,在效能與反應中間取得最佳的平衡,未來若 Windows 改版,造成間隔時間縮短時,也可以用最小時間睡眠。
長時間睡眠,通常是屬於長時間等待,並允許較大的時間誤差,但是睡太久,程式本身自己也不回應任何事件,反而會讓人誤會程式當掉了,所以一般來說,每次睡眠最好別超過 500 ms,若要超過 500 ms ,最好改用 API WaitForSingleObject 來等待,這樣也能立即回應事件。
因此最好自行包裝 DoEvents 來使用:

VBNET

Public Sub MyDoEvents(Optional ByVal dwMilliseconds As Integer = 1)

     Application.DoEvents()

     System.Threading.Thread.Sleep(dwMilliseconds)

End Sub

廣告
Categories: 技術分享 | 9 則迴響

文章分頁導航

9 thoughts on “VB6/VBNET CPU 資源釋出

  1. 子璉

    VB6 的因為在我網站上已經有放了,所以網誌這邊沒特別寫,事實上 VBNET 的網誌這邊也簡化了,我自己用的比較複雜。
    VB6 的 MyDoEvents:
    http://tlcheng.twbbs.org/TLCheng/Net/NetList.aspx?Action=Function&Module=31&Function=219

    喜歡

  2. 子璉

    我在這邊有做相關的回應,建議去看一下原文:
    KB-測試Thread.Sleep的精確度:http://blog.darkthread.net/blogs/darkthreadtw/archive/2007/03/24/657.aspx
    我把我自己的回應撿回來:
    # 璉璉 said on March 28, 2007 9:04 PM:

    剛剛從我的 live spaces 那邊看到推薦來源是這邊,就過來喵了一下…
    關於這篇,我有幾篇相關的文章:
    VB6/VBNET CPU 資源釋出:http://tlcheng.spaces.live.com/blog/cns!145419920BFD55A7!1640.entry
    MyWait 函數:http://tlcheng.twbbs.org/TLCheng/Net/NetList.aspx?Action=Function&Module=31&Function=220
    Sleep 每次睡,基本上在 WinNT 是 10ms,Win9x 是 54ms,這個在MSDN有提,可以直接搜尋 10 AND 54。
    但部份硬體可以低於這個值,讓系統可以睡的更精確,是否能睡的更精確,可以用 API QueryPerformanceFrequency 看看頻率是否與本機 CPU 頻率接近。
    我曾經有一台電腦 P4 3G 的電腦,那時用的是華碩主機板,用上面 API 測出來的 QueryPerformanceFrequency 約是 2.997 G,所以那時做上面那個 MyWait 函數時,可以精確到秒以下 5 位,也就是 0.01 ms,而誤差小於 5% ,也就是誤差小於 0.0005 ms (測試範例詳見上面網址說明) ,後來我不小心把主機板燒了,換了一塊技嘉主機板,南北橋雖然都相同,但是卻沒有那麼高的解析度,用 QueryPerformanceFrequency 跑就只有 1193180 (可用 Google 查,有的人乾脆當常數,關鍵字 QueryPerformanceFrequency 1193180) ,我現在這台 C2D E6400 的 CPU 用華碩 P5B 跑,QueryPerformanceFrequency ,得到的值是  2135090000 ,跟系統、內容的 CPU 時脈 2.14GHz 差不多,而跑上面 MyWait 得到:
    ? MyWait(0.001, False), MyWait(0.001, True) , MyWait(0.001, True, 1)
    1.00014519294269E-03        1.00118683521538E-03        1.70647232669349E-03
    第二、三個會呼叫 Sleep 睡 0, 1 ms,可以看得出來睡覺不會睡到 10 ms。
    所以我覺得是硬體的問題,而硬體是否允許 Sleep 睡覺小於 10 ms ,可以比對 QueryPerformanceFrequency 回傳值是否大於 1193180 來判斷。
     
     
     

    喜歡

  3. 子璉

    # 璉璉 said on March 28, 2007 9:20 PM:

    補充:
    所以說 MSDN 在很早就有揭露這個訊息,並不需要特別去測試,在一般電腦上時間最小解析度是 10ms/ 54ms (WinNT/Win9x),但是若在硬體有更精確的時脈支援下,就可以達到 1ms,所以 Sleep 的精確度是 目標值+- 1ms (+- 1ms 是解析度限制造成誤差) ,若需要使用更高解析度的時間處理,就要改用
    QueryPerformanceFrequency / QueryPerformanceCounter 。
    註:VBNET 版我也有類似函數,不過懶的整理,所以沒上線。

    # 璉璉 said on March 28, 2007 9:27 PM:

    再補充:
    54 ms 是以前 386/486 主機板每秒震盪 18.4 Hz 算出來的:
    1 / 18.4 = 0.0543478260 = 0.054 s = 54 ms
    所以以前在 Win3.x 的年代最小也是 54 ms ,但是那時候的 WinNT 3.5/3.51 已經支援到 10 ms,以前要高解析度的時脈要用 WinNT 來跑。
    註:WinNT 是 MSDN 定義的縮寫,表示 NT3.x/4/Win2k(5.0)/WinXP(5.1)/Win2003(5.2)/Vista(6.0)

    喜歡

  4. Unknown

    您好
    我想請問一下
    我的VB程式有用您所寫的"MyWait"這個函數但不知在函數中的mySecond=0.1秒時不知是否有效果???還是說小於1秒時以1秒來計算勒???
    謝謝
     

    喜歡

  5. 子璉

    我不知道你的引用來原是指哪邊,若是下面這個位置的話:
    http://tlcheng.twbbs.org/TLCheng/Net/NetList.aspx?Action=Function&Module=31&Function=220
    在範例已經展示了 十萬分之一秒 及 千分之一秒 ,以該例來說是可以小於 0.1 秒。

    喜歡

  6. 子璉

    在 VS2005 線上手冊有:
    ms-help://MS.MSDNQTR.v80.cht/MS.MSDN.v80/MS.WIN32COM.v10.en/sysinfo/base/windows_time.htm
    程式碼區塊
    Windows Time
    Windows time is the number of milliseconds elapsed since the system started running. This format exists primarily for backward compatibility with 16-bit Windows. To ensure that applications designed for 16-bit Windows continue to run successfully, the GetTickCount function returns the current Windows time.You typically use the GetTickCount or GetTickCount64 function to compare the current Windows time with the time returned by the GetMessageTime function. GetMessageTime returns the Windows time when the specified message was created. GetTickCount is limited to the resolution of the system timer.The system timer runs at approximately 10ms. Windows Me/98/95: The system timer runs at approximately 55ms.If you need a higher resolution timer, use a multimedia timer or a high-resolution timer.You can use the System Up Time performance counter to obtain the time elapsed since the computer was started.
    Send comments about this topic to Microsoft
    Build date: 2/1/2007

    喜歡

  7. 子璉

    新版的 msdn 內容有做調整,根本不寫 Win9x 了:
    http://msdn.microsoft.com/en-us/library/ms725496(VS.85).aspx
    Windows Time
    Windows TimeWindows time is the number of milliseconds elapsed since the system was last started. This format exists primarily for backward compatibility with 16-bit Windows. To ensure that applications designed for 16-bit Windows continue to run successfully, the GetTickCount function returns the current Windows time.You typically use the GetTickCount or GetTickCount64 function to compare the current Windows time with the time returned by the GetMessageTime function. GetMessageTime returns the Windows time when the specified message was created. GetTickCount and GetTickCount64 are limited to the resolution of the system timer, which is approximately 10 milliseconds to 16 milliseconds. The elapsed time retrieved by GetTickCount or GetTickCount64 includes time the system spends in sleep or hibernation. If you need a higher resolution timer, use the QueryUnbiasedInterruptTime function, a multimedia timer, or a high-resolution timer. The elapsed time retrieved by the QueryUnbiasedInterruptTime function includes only time that the system spends in the working state.Windows Server 2008, Windows Vista, Windows Server 2003, and Windows XP/2000: The QueryUnbiasedInterruptTime function is available starting with Windows 7 and Windows Server 2008 R2.You can use the System Up Time performance counter to obtain the number of seconds elapsed since the computer was started. This performance counter can be retrieved from the performance data in the registry key HKEY_PERFORMANCE_DATA. The value returned is an 8-byte value. For more information, see Performance Counters.
    Send comments about this topic to Microsoft
    Build date: 10/8/2009

    喜歡

  8. 子璉

    另外再跟黑暗執行緒大文中討論的另一篇網址為:http://blog.darkthread.net/blogs/darkthreadtw/archive/2007/03/29/673.aspx

    喜歡

  9. 引用通告: c#的timer 每一次延遲時間不盡相同 | Hello, Visual Basic program…

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

您的留言將使用 WordPress.com 帳號。 登出 / 變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 / 變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 / 變更 )

Google+ photo

您的留言將使用 Google+ 帳號。 登出 / 變更 )

連結到 %s

在WordPress.com寫網誌.

%d 位部落客按了讚: