我们的语音平台程序,需要运行在大线路并发环境,要求有很高的性能。
因为是多线程程序,在几百上千个线程同时加载脚本的时候,千军万马过独木桥,往往导致极大的CPU开销,比较好的办法就是在每个加载线程内对CPU占用进行判断,如果占用率小于某个值,就继续运行,否则就Sleep(),等候CPU占用的下降。
win32 API并没有提供直接得到CPU占用率的函数,但提供GetProcessTimes()函数可以得到进程占用的CPU时间,通过和实际时间的流逝相比,可以得到某进程占用CPU的比率。
好了,下面就是完整的C++代码。
//
得到当前进程的CPU占用率
class GetCPUPercentage
... {
private:
CRITICAL_SECTION cs; // 供多线程同步的临界区变量
HANDLE hd; // 空闲进程的句柄
DWORD t1; // 时间戳
int percent; // 最近一次计算的CPU占用率
__int64 oldp;
__int64 FileTimeToInt64(const FILETIME& time);
int GetTime(__int64& proc); // 得到进程占用的CPU时间
public:
GetCPUPercentage();
~GetCPUPercentage();
int Get(); // 得到CPU占用率
} ;
GetCPUPercentage::GetCPUPercentage()
... {
InitializeCriticalSection(&cs); // 初始化线程临界区变量
percent = 0; // 初始的占用率
DWORD pid = GetCurrentProcessId(); // 得到当前进程id
hd = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); // 通过id得到进程的句柄
if( hd==NULL )...{
return;
}
// 得到初始时刻的值
GetTime(oldp);
t1 = GetTickCount();
}
GetCPUPercentage:: ~ GetCPUPercentage()
... {
if( hd!=NULL )...{
CloseHandle(hd);
}
DeleteCriticalSection(&cs);
}
// 时间格式转换
__int64 GetCPUPercentage::FileTimeToInt64( const FILETIME & time)
... {
ULARGE_INTEGER tt;
tt.LowPart = time.dwLowDateTime;
tt.HighPart = time.dwHighDateTime;
return(tt.QuadPart);
}
// 得到进程占用的CPU时间
int GetCPUPercentage::GetTime(__int64 & proc)
... {
FILETIME create;
FILETIME exit;
FILETIME ker; // 内核占用时间
FILETIME user; // 用户占用时间
FILETIME now;
if( !GetProcessTimes(hd, &create, &exit, &ker, &user) )...{
return(-1);
}
proc = (FileTimeToInt64(ker) + FileTimeToInt64(user))/10000;
return(0);
}
// 进行换算
int GetCPUPercentage::Get()
... {
if( hd==NULL )
return(0);
EnterCriticalSection(&cs);
DWORD t2 = GetTickCount();
DWORD dt = t2 - t1;
if( dt>139 )...{ // 毫秒数。用一个比较少的时间片作为计算单位,这个值可修改
__int64 proc;
GetTime(proc);
percent = ((proc-oldp)*100)/dt;
t1 = t2;
oldp = proc;
}
LeaveCriticalSection(&cs);
return(percent);
}
// 定义一个全局变量
GetCPUPercentage _cpu;
// 下面是用C++Bulider写的测试例子:
// --------------------------
// 在用一个时钟不停地显示当前的CPU占用率
void __fastcall TForm1::Timer1Timer(TObject * Sender)
... {
Label1->Caption = _cpu.Get();
}
// ---------------------------------------------------------------------------
// 再弄个按钮
LRESULT WINAPI TestThread(LONG lParam)
... {
int n = lParam;
for(int i=0 ;i<n; i++)...{
Form1->Label2->Caption = i;
Sleep(12);
}
return(0);
}
// 点击这个按钮会创建一些线程来把CPU整的繁忙些
void __fastcall TForm1::Button1Click(TObject * Sender)
... {
int n = atoi(Edit1->Text.c_str());
DWORD dwThreadid;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TestThread,
(void*)n, 0, &dwThreadid);
}
// ---------------------------------------------------------------------------
class GetCPUPercentage
... {
private:
CRITICAL_SECTION cs; // 供多线程同步的临界区变量
HANDLE hd; // 空闲进程的句柄
DWORD t1; // 时间戳
int percent; // 最近一次计算的CPU占用率
__int64 oldp;
__int64 FileTimeToInt64(const FILETIME& time);
int GetTime(__int64& proc); // 得到进程占用的CPU时间
public:
GetCPUPercentage();
~GetCPUPercentage();
int Get(); // 得到CPU占用率
} ;
GetCPUPercentage::GetCPUPercentage()
... {
InitializeCriticalSection(&cs); // 初始化线程临界区变量
percent = 0; // 初始的占用率
DWORD pid = GetCurrentProcessId(); // 得到当前进程id
hd = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); // 通过id得到进程的句柄
if( hd==NULL )...{
return;
}
// 得到初始时刻的值
GetTime(oldp);
t1 = GetTickCount();
}
GetCPUPercentage:: ~ GetCPUPercentage()
... {
if( hd!=NULL )...{
CloseHandle(hd);
}
DeleteCriticalSection(&cs);
}
// 时间格式转换
__int64 GetCPUPercentage::FileTimeToInt64( const FILETIME & time)
... {
ULARGE_INTEGER tt;
tt.LowPart = time.dwLowDateTime;
tt.HighPart = time.dwHighDateTime;
return(tt.QuadPart);
}
// 得到进程占用的CPU时间
int GetCPUPercentage::GetTime(__int64 & proc)
... {
FILETIME create;
FILETIME exit;
FILETIME ker; // 内核占用时间
FILETIME user; // 用户占用时间
FILETIME now;
if( !GetProcessTimes(hd, &create, &exit, &ker, &user) )...{
return(-1);
}
proc = (FileTimeToInt64(ker) + FileTimeToInt64(user))/10000;
return(0);
}
// 进行换算
int GetCPUPercentage::Get()
... {
if( hd==NULL )
return(0);
EnterCriticalSection(&cs);
DWORD t2 = GetTickCount();
DWORD dt = t2 - t1;
if( dt>139 )...{ // 毫秒数。用一个比较少的时间片作为计算单位,这个值可修改
__int64 proc;
GetTime(proc);
percent = ((proc-oldp)*100)/dt;
t1 = t2;
oldp = proc;
}
LeaveCriticalSection(&cs);
return(percent);
}
// 定义一个全局变量
GetCPUPercentage _cpu;
// 下面是用C++Bulider写的测试例子:
// --------------------------
// 在用一个时钟不停地显示当前的CPU占用率
void __fastcall TForm1::Timer1Timer(TObject * Sender)
... {
Label1->Caption = _cpu.Get();
}
// ---------------------------------------------------------------------------
// 再弄个按钮
LRESULT WINAPI TestThread(LONG lParam)
... {
int n = lParam;
for(int i=0 ;i<n; i++)...{
Form1->Label2->Caption = i;
Sleep(12);
}
return(0);
}
// 点击这个按钮会创建一些线程来把CPU整的繁忙些
void __fastcall TForm1::Button1Click(TObject * Sender)
... {
int n = atoi(Edit1->Text.c_str());
DWORD dwThreadid;
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TestThread,
(void*)n, 0, &dwThreadid);
}
// ---------------------------------------------------------------------------