天天看點

VC程式運作時間的測試函數

介紹

       我們在測試一個函數運作時間,或者判斷一個算法的時間效率,或者在程式中我們需要一個定時器,定時執行一個特定的操作,比如在多媒體中,比如在遊戲中等,都會用到時間函數。還比如我們通過記錄函數或者算法開始和截至的時間,然後利用兩者之差得出函數或者算法的運作時間。編譯器和作業系統為我們提供了很多時間函數,這些時間函數的精度也是各不相同的,是以,如果我們想得到準确的結果,必須使用合适的時間函數。現在我就介紹windows下的幾種常用時間相關函數。

1:Sleep函數

使用:sleep(1000),在Windows和Linux下1000代表的含義并不相同,Windows下的表示1000毫秒,也就是1秒鐘;Linux下表示1000秒,Linux下使用毫秒級别的函數可以使用usleep。定義在windows.h頭檔案中。

原理:sleep函數是使調用sleep函數的線程休眠,線程主動放棄時間片。當經過指定的時間間隔後,再啟動線程,繼續執行代碼。Sleep函數并不能起到定時的作用,主要作用是延時。在一些多線程中可能會看到sleep(0);其主要目的是讓出時間片。

精度:sleep函數的精度非常低,當系統越忙它精度也就越低,有時候我們休眠1秒,可能3秒後才能繼續執行。它的精度取決于線程自身優先級、其他線程的優先級,以及線程的數量等因素。

2:MFC下的timer事件

       使用:1.調用函數SetTimer()設定定時間隔,如SetTimer(0,100,NULL)即為設定100毫秒的時間間隔;2.在應用程式中增加定時響應函數OnTimer(),并在該函數中添加響應的處理語句,用來完成時間到時的操作。

    原理:同sleep函數一樣。不同的是timer是一個定時器,可以指定回調函數,預設為OnTimer()函數。

    精度:timer事件的精度範圍在毫米級别,系統越忙其精度也就越差。

3:C語言下的time

       使用:time_t t;  time(&t); time函數是擷取目前時間。定義在time.h頭檔案中。他擷取目前的系統時間,接受time_t類型的指針參數,傳回的結果是一個time_t類型,其實就是一個大整數,其值表示從CUT(Coordinated Universal Time)時間1970年1月1日00:00:00(稱為UNIX系統的Epoch時間)到目前時刻的秒數。然後可調用localtime将CUT時間轉換為本地時間(我們是+8區,比CUT多8個小時)并轉成struct tm類型,接收time_t類型的指針,傳回struct tm類型的指針,該類型的各資料成員分别表示年月日時分秒。最後可以調用asctime函數将struct tm類型對象轉換成string類型對象,他接收struct tm類型的指針,傳回string類型的對象,表示着當地的年月日時間。

    原理:time函數主要用于擷取目前時間,比如我們做一個電子時鐘程式,就可以使用此函數,擷取系統目前的時間。

    精度:秒級别

    例子:

 #include<string>

#include<time.h>

#include<iostream>

using std::string;

using std::cout;

using std::endl;

void main()

{

time_t t;

struct tm* tm_time;

time(&t);

tm_time=localtime(&t);

string s_time=asctime(tm_time);

cout<<"Time is: "<<s_time<<endl;

}

4:COM對象中的COleDateTime,COleDateTimeSpan類

    使用:COleDateTime start_time = COleDateTime::GetCurrentTime();

COleDateTimeSpan end_time = COleDateTime::GetCurrentTime()-start_time;

While(end_time.GetTotalSeconds() < 2)

{

// 處理延時或定時期間能處理其他的消息

DoSomething()

end_time = COleDateTime::GetCurrentTime-start_time;

}

原理:以上代表延時2秒,而這兩秒内我們可以循環調用DoSomething(),進而實作在延時的時候我們也能夠處理其他的函數,或者消息。COleDateTime,COleDateTimeSpan是MFC中CTime,CTimeSpan在COM中的應用,是以,上面的方法對于CTime,CTimeSpa同樣有效。

       精度:秒級别

5:C語言下的時鐘周期clock()

       使用:  

clock_t start = clock();

Sleep(100);

clock_t end = clock();

double d = (double)(start - end) / CLOCKS_PER_SEC;

       原理:clock()是擷取計算機啟動後的時間間隔。

精度:ms級别,對于短時間内的定時或者延時可以達到ms級别,對于時間比較長的定時或者延遲精度還是不夠。在windows下頻率CLOCKS_PER_SEC為1000。

6:Windows下的GetTickCount()

使用:  

DWORD start = GetTickCount();

Sleep(100);

DWORD end = GetTickCount();

原理:GetTickCount()是擷取系統啟動後的時間間隔。通過進入函數開始定時,到退出函數結束定時,進而可以判斷出函數的執行時間,這種時間也并非是函數或者算法的真實執行時間,因為在函數和算法線程不可能一直占用CPU,對于所有判斷執行時間的函數都是一樣,不過基本上已經很準确,可以通過查詢進行定時。GetTickCount() 和Clock()函數是向主機闆BIOS要real time clock時間,會有中斷産生,以及延遲問題。

精度:WindowsNT 3.5以及以後版本精度是10ms,它的時間精度比clock函數的要高,GetTickCount()常用于多媒體中。

7:Windows下timeGetTime

使用:需要包含Mmsystem.h,Windows.h,加入靜态庫Winmm.lib.(靜态庫的添加參考:http://topic.csdn.net/u/20090922/19/86ad7893-906a-42d2-baa6-dda26d911b1d.html)

timeBeginPeriod(1);

DWORD start = timeGetTime();

Sleep(100);

DWORD end = timeGetTime();

timeEndPeriod(1);

原理:timeGetTime也時常用于多媒體定時器中,可以通過查詢進行定時。通過查詢進行定時,本身也會影響定時器的定時精度。

精度:毫秒,與GetTickCount()相當。但是和GetTickCount相比,timeGetTime可以通過timeBeginPeriod,timeEndPeriod設定定時器的最小解析精度, timeBeginPeriod,timeEndPeriod必須成對出現。

8:windows下的timeSetEvent

使用:還記的VC下的Timer嗎?Timer是一個定時器,而以上我們提到幾種時間函數或者類型,實作定時功能隻能通過輪訓來實作,也就是必須另外建立一個線程單獨處理,這樣會影響定時精度,好在windows提供了内置的定時器timeSetEvent,函數原型為

MMRESULT timeSetEvent( UINT uDelay, //以毫秒指定事件的周期

UINT uResolution, //以毫秒指定延時的精度,數值越小定時器事件分辨率越高。預設值為1ms

LPTIMECALLBACK lpTimeProc, //指向一個回調函數

WORD dwUser, //存放使用者提供的回調資料

UINT fuEvent )// 标志參數,TIME_ONESHOT:執行一次;TIME_PERIODIC:周期性執行

       具體應用時,可以通過調用timeSetEvent()函數,将需要周期性執行的任務定義在 lpFunction回調函數中(如:定時采樣、控制等),進而完成所需處理的事件。需要注意的是:任務處理的時間不能大于周期間隔時間。另外,在定時器使用完畢後,應及時調用timeKillEvent()将之釋放。(參考:http://hi.baidu.com/shenshuilanl/blog/item/db6443d07b66438fa0ec9cce.html )

原理:可以了解為代回調函數的timeGetTime

精度:毫秒,timeSetEvent可以通過timeBeginPeriod,timeEndPeriod設定定時器的最小解析精度, timeBeginPeriod,timeEndPeriod必須成對出現。

9:高精度時控函數QueryPerformanceFrequency,QueryPerformanceCounter

使用:定義在windows.h頭檔案裡。

LARGE_INTEGER m_nFreq;

LARGE_INTEGER m_nBeginTime;

LARGE_INTEGER nEndTime;

QueryPerformanceFrequency(&m_nFreq); //擷取時鐘頻率,傳回bool類型的值,非零,硬體支援高精度計數器;零,硬體不支援,讀取失敗。

QueryPerformanceCounter(&m_nBeginTime);//擷取時鐘計數,同樣傳回bool類型的值,非零,硬體支援高精度計數器;零,硬體不支援,讀取失敗。

Sleep(100);

QueryPerformanceCounter(&nEndTime);//擷取時鐘計數

cout << (nEndTime.QuadPart-m_nBeginTime.QuadPart)*1000/m_nFreq.QuadPart << endl;

原理:CPU上也有一個計數器,以機器的clock為機關,可以通過rdtsc讀取,而不用中斷,是以其精度與系統時間相當。

精度:計算機擷取硬體支援,精度比較高,可以通過它判斷其他時間函數的精度範圍。

10小結:以上提到常用的9種時間函數,由于他們的用處不同,是以他們的精度也不盡相同,是以如果簡單的延時可以用sleep函數,稍微準确的延時可以使用clock函數,GetTickCount函數,更進階的實用timeGetTime函數;簡單的定時事件可以用Timer,準确地可以用timeSetEvent;或取一般系統時間可以通time,或者CTime,或者COleDateTime,擷取準确的時間可以用clock,或者GetTickCount函數,或者timeGetTime函數,而擷取準确地系統時間要使用硬體支援的QueryPerformanceFrequency函數,QueryPerformanceCounter函數。

在linux下擷取時間的函數可以參考:linux下擷取時間的函數

繼續閱讀