前两天曾经发过贴,请教如何解决界面切换困难的问题,听了一些朋友的建议,决定采用多线程解决,可是发现还是没效果,我把问题简单描述一下,请各位看客帮忙参谋参谋,多提宝贵意见。
在一个基于CFormView的多文档程序中,当切换界面时有个界面反应很迟钝,后来发现是一个数据采集函数太耗时了,该函数执行完大约需要2~3秒。而且该函数还要每隔大约3秒钟就要被调用一次。后来我决定将该函数放到一个线程函数中执行,该函数执行完再将结果赋给一个全局的结构体数组。然后在主线程中用虚拟列表将保存在结构体数组中的数据显示到列表中。思路大致就是这样的,代码大致如下://原来的方案:void CPidHistgramView::ProcessData() //约每3秒被调用一次
{
ReceiveData(); //从动态库中读数据,耗时大约2~3秒
m_virtualList.SetItemCount(m_listCount); //设置列表中总的数据条目数
}void CPidHistgramView::ReceiveData()
{
for(int i=0;i<m_listCount;i++)
{
//调用库中函数获取数据,耗时约3秒
.....
.....
////
//将得到的数据赋给全局结构体数组
strcpy( g_data[i].str1,sValue1);
strcpy( g_data[i].str2,sValue2);
...
strcpy( g_data[i].str8,sValue8);
}} 因为数据采集函数太耗时,所以将其放入到工作线程中,后来的采用方案在工作线程中建立一个消息队列,获取工作线程的WM_TIMER消息,每3秒发送一次。在工作线程的WM_TIMER响应函数里再调用全局函数ReceiveData()采集数据,代码大致如下:// 线程函数,在OnInitialUpdate()函数中调用 AfxBeginThread(ThreadFunc,(LPVOID)NULL)启动UINT ThreadFunc(LPVOID lParam)
{
int nTimerID=SetTimer(NULL,0,3000,NULL); // 设定一个3秒间隔的定时器 MSG msg;
PeekMessage(&msg,NULL,WM_USER,WM_USER,PM_NOREMOVE);
DWORD dEndWord;
BOOL bRun=TRUE;
while (bRun)
{
dEndWord=WaitForSingleObject(eventEnd,0); //查询"结束事件"状态,立即返回
if(dEndWord==WAIT_OBJECT_0) //可以正常退出
{
KillTimer(NULL,nTimerID);
return 0;
}
if (GetMessage(&msg,NULL,NULL,NULL))
{
switch(msg.message)
{
case WM_TIMER:
{
ReceiveData(); //从动态库中读数据,耗时大约2~3秒 }
break;
default:
break;
}
}
}
return 0;
}void CPidHistgramView::ProcessData() //约每3秒被调用一次
{
m_virtualList.SetItemCount(m_listCount); //设置列表中总的数据条目数
} 主要代码如上所示,主要思路是程序运行时就启动工作线程,工作线程每3秒发送一个定时器消息,ReceiveData()采集函数大约要费时2秒多。ProcessData()函数每3秒被调用一次,用来刷新界面上的列表控件,显示时用到了CVirtualList Control 技术。 按照原来的设想,将采集函数放到工作线程后CPU应该会降下来,不会再阻塞主线程,可是运行发现,CPU的占有率还是很高,达到90%以上,调试发现主要问题出在ReceiveData()这个采集函数上,当把这个函数注销后,CPU就很低了。而且用虚拟列表显示时按说应该每调用一次,界面就一次完整的把数据显示出来,可现在发现,当每3秒调用ProcessData()函数刷新界面时,列表有时是由上到下一行一行显示数据,效果非常差,搞不清楚用了虚表怎么还会这样,难道是因为CPU太忙碌了的缘故?
像我这种情况该怎么解决?
在一个基于CFormView的多文档程序中,当切换界面时有个界面反应很迟钝,后来发现是一个数据采集函数太耗时了,该函数执行完大约需要2~3秒。而且该函数还要每隔大约3秒钟就要被调用一次。后来我决定将该函数放到一个线程函数中执行,该函数执行完再将结果赋给一个全局的结构体数组。然后在主线程中用虚拟列表将保存在结构体数组中的数据显示到列表中。思路大致就是这样的,代码大致如下://原来的方案:void CPidHistgramView::ProcessData() //约每3秒被调用一次
{
ReceiveData(); //从动态库中读数据,耗时大约2~3秒
m_virtualList.SetItemCount(m_listCount); //设置列表中总的数据条目数
}void CPidHistgramView::ReceiveData()
{
for(int i=0;i<m_listCount;i++)
{
//调用库中函数获取数据,耗时约3秒
.....
.....
////
//将得到的数据赋给全局结构体数组
strcpy( g_data[i].str1,sValue1);
strcpy( g_data[i].str2,sValue2);
...
strcpy( g_data[i].str8,sValue8);
}} 因为数据采集函数太耗时,所以将其放入到工作线程中,后来的采用方案在工作线程中建立一个消息队列,获取工作线程的WM_TIMER消息,每3秒发送一次。在工作线程的WM_TIMER响应函数里再调用全局函数ReceiveData()采集数据,代码大致如下:// 线程函数,在OnInitialUpdate()函数中调用 AfxBeginThread(ThreadFunc,(LPVOID)NULL)启动UINT ThreadFunc(LPVOID lParam)
{
int nTimerID=SetTimer(NULL,0,3000,NULL); // 设定一个3秒间隔的定时器 MSG msg;
PeekMessage(&msg,NULL,WM_USER,WM_USER,PM_NOREMOVE);
DWORD dEndWord;
BOOL bRun=TRUE;
while (bRun)
{
dEndWord=WaitForSingleObject(eventEnd,0); //查询"结束事件"状态,立即返回
if(dEndWord==WAIT_OBJECT_0) //可以正常退出
{
KillTimer(NULL,nTimerID);
return 0;
}
if (GetMessage(&msg,NULL,NULL,NULL))
{
switch(msg.message)
{
case WM_TIMER:
{
ReceiveData(); //从动态库中读数据,耗时大约2~3秒 }
break;
default:
break;
}
}
}
return 0;
}void CPidHistgramView::ProcessData() //约每3秒被调用一次
{
m_virtualList.SetItemCount(m_listCount); //设置列表中总的数据条目数
} 主要代码如上所示,主要思路是程序运行时就启动工作线程,工作线程每3秒发送一个定时器消息,ReceiveData()采集函数大约要费时2秒多。ProcessData()函数每3秒被调用一次,用来刷新界面上的列表控件,显示时用到了CVirtualList Control 技术。 按照原来的设想,将采集函数放到工作线程后CPU应该会降下来,不会再阻塞主线程,可是运行发现,CPU的占有率还是很高,达到90%以上,调试发现主要问题出在ReceiveData()这个采集函数上,当把这个函数注销后,CPU就很低了。而且用虚拟列表显示时按说应该每调用一次,界面就一次完整的把数据显示出来,可现在发现,当每3秒调用ProcessData()函数刷新界面时,列表有时是由上到下一行一行显示数据,效果非常差,搞不清楚用了虚表怎么还会这样,难道是因为CPU太忙碌了的缘故?
像我这种情况该怎么解决?
这种情况,必须优化你的接收处理过程ReceiveData,处理数据要比接收数据耗时的多,一定要优化数据处理的算法。
///这是一个好主意。我试过了,设置Sleep(30),界面效果稍有改善,但还是不能令人满意,设置Sleep(100),效果不错,切换也不太迟钝,但带来的问题是数据更新周期变长了,原来3秒多更新一次数据,现在有时要7秒多。真的很难两全啊。
switch case 多分枝语句,共有多条分枝。
void CPidHistgramView::ReceiveData()
{
//循环体执行完大约3秒钟,该怎么改进结构?
for(int i=0;i <m_listCount;i++)
{
switch( nPriority ) // 级别
{
case 1:
...
break;
case 2:
...
break;
case 3:
...
break;
case 4:
...
break;
case 5:
...
break;
case 6:
...
break;
case 7:
...
break;
case 8:
...
break;
default:
break;
}
////
}
} 想请教各位大侠,像这种情况下,怎么改进结构才能提高运行效率?
SwitchToThread
{
DWORD dwStart = GetTickCount() ;
while( TRUE )
{
MSG msg;
while( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
{
::TranslateMessage( &msg );
::DispatchMessage( &msg );
}
if ( GetTickCount() - dwStart > (DWORD)iMS )
{
break ;
}
}
}优化采集算法,将采集分散在线程多次执行中,如果涉及到多点采集,可以使用多个线程进行
界面刷新频率可以降低,一般2~3Hz就可以了