当前位置:C++技术网 > 资讯 > 如何实现实时统计速度

如何实现实时统计速度

更新时间:2015-06-25 14:11:13浏览次数:1+次

    如何实现实时统计速度?
    其实这个说起来不难。但是实际操作确实会有些问题的,稍不注意,就得不到自己要的效果。
    首先要明白时间统计的原理。在统计速度时,可不要使用系统时间来计算,因为那样也太不准确了。使用函数GetTickCount精度稍微高些,这个精度是ms级别,对于一般的场合都使用,对于严格的要求,还是不够,那就要使用多媒体计时器或者高精度计时器。这两个的资料,请查阅MSDN。
    时间统计,其实就是在读取写入或者下载上传时,完成一批数据后,使用这批数据量除以使用的时间,得到的就是速度。这个道理大家都懂。但是实际操作确实有些问题的。下面来看看。
    在循环中实时显示速度,也就是说,读取1GB数据,每次读取1MB,那么久是10GB除以1MB次,即1K(1000)次。在这1000次中,每操作一次数据,就会形成数据流,完成操作后,就花费了时间,这时使用数据量除以时间的得到的自然就是实时的速度。所以我们会在操作前获得一次时间,操作后获得时间,得到差值,差值就是使用的时间。速度就出来了。但是有时候发现,差值时间是0.这样程序崩溃,出现除0错误。你知道是为什么吗?
    这个问题就是我们经常遇见的问题。刚开始做这个,以为是很简单。但是做着却发现很不如意,也不知道问题出在哪了。接下来,与你说说原因。
    上面提到了精度的问题。GetTickCount的精度是毫秒级别。加入每次操作的数据量很小,在现代的CPU环境下,处理速度极快,毫秒级实在是太长了,所以就不精确了。数据量小,一毫秒都没用,数据就处理完了。开始和结束的毫秒值一样,这样时间差就为0了,这样就出现了除零错误。这种问题,刚接触这个方面的编程的往往就不知道,以为很简单,实则没那么简单。在这种情况下,要处理好精度问题,就要想办法了,要让时间形成差值不为零即可。当然不要人为的延时,那是错误的。


    解决精度问题,可以从两个方面着手。
    1. 第一个就是数据量,保证足够的数据量,就可以保证需要一定毫秒数的时间才能完成。比如说我把每次操作的数据量提到100MB,这样,自然就耗时比较长,加入总线速度为100M/S,这样一次操作就要耗时1S多(考虑还有其他统计操作耗时),这样就把精确度提到秒级级别,那么GetTickCount作为毫秒级的代表,完全是没有问题的。
    2. 第二个就是拉长统计时间。使用取模操作,每个一定数量统计一次结果,这样时间的操作次数的累积,知道累积的数据量和累积的时间,自然也就是把精确度拉到毫秒级或者秒级了,这样也不存在精度问题。
    不管你是用什么方法,都是围绕这两个方法来的。当然,也可以使用精确度更高的,比如纳秒级的。不过一般情况下用不着。
    下面说明一下GetTickCount函数的使用。
    原型声明:

DWORD GetTickCount(VOID);

     直接返回一个DWORD值,这个值代表距离系统启动的时间值,每次调用就得到调用时相对于系统启动时间的值。要统计相隔时间,只要调用两次,相减就得到两次统计之间的差值。这个数学道理很简单的。这个函数存储的值得类型是DWORD类型,因此,持续统计到49.7天后又归零了。
    使用此函数需要包含Winbase.h和Windows.h两个头文件。Windows系列平台都支持。
    下面给出基本使用代码示例:

    DWORD dwStart = GetTickCount();// - 这中间是你操作数据操作的地方    
    memset(缓冲地址,数值,字节大小);// - 填充数据    
    DWORD dwEnd = GetTickCount();    
    DWORD dwSpan = dwEnd - dwStart;// - 得到毫秒数    
    DWORD dwSpeed = 数据字节量*1000/1024/dwSpan;// - 得到KB/s
     代码注意:
    1. 提高数据量:把填充的字节数提高到一定的数值,多尝试。
    2. dwStart 和 dwEnd 相隔要足够长,保证dwSpan 不能为零,最好对dwSpan进行检测,确保不为零。
    以下是MFC中使用的代码:
    CFile file;
    file.Open(_T("F:\\test.dat"),CFile::modeReadWrite | CFile::modeCreate);
    BYTE * pBuf = new BYTE[1024*1024];
    memset(pBuf,0x00,1024*1024);
    DWORD dwBeginTime = GetTickCount();
    for(int i=0;i<1024;i++)
    {
        file.Write(pBuf,1024*1024);
        if (i%50==0)
        {
            DWORD dwEndTime;
            DWORD dwSpanTime;
            dwEndTime = GetTickCount();
            dwSpanTime = dwEndTime - dwBeginTime;
            CString str;
            str.Format(_T("速度:%d M/S ,用时:%d S"),(i*1000/dwSpanTime),dwSpanTime/1000);
            //::MessageBox(NULL,str,_T("speed"),MB_OK);
        }
    }
    delete []pBuf;

    以上代码就不仔细解释了。核心结构都是上文解释过的。如果时间隔得远就是那一段时间的平均速度,如果时间相隔短,则近似为瞬时速度。