最近有個(gè)項(xiàng)目需要準(zhǔn)確計(jì)量時(shí)間,在網(wǎng)上搜索了一些相關(guān)資料,匯總摘抄在此。
Windows是一個(gè)搶占式多任務(wù)系統(tǒng),要準(zhǔn)確測(cè)量時(shí)間(達(dá)到毫秒級(jí)精度)是比較困難的,下面簡(jiǎn)易對(duì)比分析一下Windows所提供的毫秒級(jí)時(shí)間相關(guān)函數(shù)。
方法1:
void WINAPI GetSystemTime(LPSYSTEMTIME lpSystemTime);
typedef struct _systemtime {
word wyear;
word wmonth;
word wdayofweek;
word wday;
word whour;
word wminute;
word wsecond;
word wmilliseconds;
} systemtime, *psystemtime;
取得當(dāng)前系統(tǒng)日期和時(shí)間,最小精度為毫秒。具體參見(jiàn)https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms724390%28v=vs.85%29.aspx
方法2:
void WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime );
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime; } FILETIME, *PFILETIME;
結(jié)構(gòu)包含一個(gè)64位的數(shù)值,代表UTC時(shí)間1601年1月1日開(kāi)始到現(xiàn)在的計(jì)數(shù)器,計(jì)數(shù)間隔為100納秒。可以通過(guò)調(diào)用FileTimeToSystemTime函數(shù)轉(zhuǎn)換為標(biāo)準(zhǔn)時(shí)分秒形式。
具體參見(jiàn)https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms724397%28v=vs.85%29.aspx
方法3:
DWORD WINAPI GetTickCount(void);
獲取從系統(tǒng)啟動(dòng)到現(xiàn)在的毫秒數(shù)。參見(jiàn)https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms724408%28v=vs.85%29.aspx
方法4:
DWORD timeGetTime(void);
也是獲取從系統(tǒng)啟動(dòng)到當(dāng)前的毫秒數(shù)值,是微軟在游戲、多媒體庫(kù)提供的一個(gè)函數(shù)。調(diào)用時(shí)需要包含Winmm.lib庫(kù)
具體參見(jiàn)https://msdn.microsoft.com/zh-cn/library/windows/desktop/dd757629%28v=vs.85%29.aspx
方法5:
BOOL WINAPI QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
這個(gè)是微軟Windows所提供最高級(jí)別的時(shí)間計(jì)數(shù)器,據(jù)稱(chēng)時(shí)戳的最高精度小于1us。參見(jiàn)https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms644904%28v=vs.85%29.aspx
照說(shuō)有這么多時(shí)間精度可供選擇,問(wèn)題應(yīng)該很好解決,但事情并不是這么簡(jiǎn)單。QueryPerformanceCounter這個(gè)最為微軟推薦的高精度時(shí)間函數(shù)是有缺陷的,當(dāng)處理器有多個(gè)內(nèi)核時(shí),QueryPerformanceCounter計(jì)數(shù)器會(huì)做相應(yīng)的調(diào)整以保持準(zhǔn)確。但由于某些BIOS的bug,線(xiàn)程切換時(shí)QueryPerformanceCounter計(jì)數(shù)器可能會(huì)返回不同的數(shù)值。因此微軟建議盡量在一個(gè)核上執(zhí)行
QueryPerformanceCounter計(jì)時(shí)。相關(guān)說(shuō)明參見(jiàn)Game Timing and Multicore Processors一文(https://msdn.microsoft.com/en-us/library/ee417693(v=vs.85).aspx)
關(guān)于QueryPerformanceCounter使用注意事項(xiàng)
1.QueryPerformanceFrequency只需要調(diào)用一次就夠了,這個(gè)頻率值在系統(tǒng)運(yùn)行期間不會(huì)改變。
2.盡量在單進(jìn)程和單線(xiàn)程、單內(nèi)核環(huán)境下調(diào)用QueryPerformanceCounter,使用 Windows API SetThreadAffinityMask可以設(shè)置某個(gè)線(xiàn)程只在單處理器執(zhí)行。
3.在多個(gè)線(xiàn)程中使用QueryPerformanceCounter可能顯著的降低多內(nèi)核系統(tǒng)的性能。
4.在系統(tǒng)休眠或者超頻情況下使用QueryPerformanceCounter計(jì)時(shí)可能會(huì)不準(zhǔn)確。
綜合比較Windows時(shí)間函數(shù),計(jì)時(shí)精度QueryPerformanceCounter > timeGetTime > GetTickCount ,GetTickCount的精度大約是55ms左右(1個(gè)Tick),timeGetTime實(shí)際上也是用QueryPerformanceCounter除以頻率換算出來(lái)的,所以應(yīng)該比GetTickCount要準(zhǔn)確些。
讀取準(zhǔn)確UTC時(shí)間GetSystemTimeAsFileTime > GetSystemTime。更準(zhǔn)確的系統(tǒng)時(shí)間讀取可以結(jié)合GetSystemTimeAsFileTime與QueryPerformanceCounter來(lái)計(jì)算。詳細(xì)可參見(jiàn)定時(shí)器:為 Windows 實(shí)現(xiàn)一個(gè)連續(xù)更新,高精度的時(shí)間供應(yīng)器一文。
英文原文在這里:https://msdn.microsoft.com/en-us/magazine/cc163996.aspx,對(duì)應(yīng)的中文翻譯看這里:http://www.vckbase.com/index.php/wv/776
關(guān)于GetSystemTimeAsFileTime與GetSystemTime的比較分析可參見(jiàn)http://www.cnblogs.com/walfud/articles/3242825.html一文。