C++ 下载各地的速度跳跃

C++ 下载各地的速度跳跃,c++,winapi,libcurl,C++,Winapi,Libcurl,我有一个使用curl从ftp下载文件的小程序。在CURLOPT_PROGRESSFUNCTION中传递的函数中,我计算下载速度,问题是下载速度到处跳跃,在2mbps的互联网连接上从512kbps跳到8mbps。我无法确定这里出了什么问题 编辑:我已更改代码以平均读数,curl下载的问题是您无法预测何时将调用TraceProgress函数,它可以在不到1秒的时间内再次调用,因此程序等待5次迭代以记录读数,并在平均前获取6次此类读数,我还考虑了自上次读取以来经过的时间(秒),因为我们不能保证Trac

我有一个使用curl从ftp下载文件的小程序。在CURLOPT_PROGRESSFUNCTION中传递的函数中,我计算下载速度,问题是下载速度到处跳跃,在2mbps的互联网连接上从512kbps跳到8mbps。我无法确定这里出了什么问题

编辑:我已更改代码以平均读数,curl下载的问题是您无法预测何时将调用TraceProgress函数,它可以在不到1秒的时间内再次调用,因此程序等待5次迭代以记录读数,并在平均前获取6次此类读数,我还考虑了自上次读取以来经过的时间(秒),因为我们不能保证TraceProgress函数将以相等的间隔调用

如果现在看起来好些了,请告诉我

代码如下:

int minorCounter = 0;
int majorCounter = 0;

int minorCycle = 4;
int majorCycle = 5;

double blockDL[6];
double blockTime[6];

int TraceProgress( void *clientp, double dltotal, double dlnow, double ultotal, double ulnow )
{

  if ( minorCounter == minorCycle )
    {

            blockDL[majorCounter] = dlnow - oldDownloadNow;

            myTimer.Tick();
            blockTime[majorCounter] = myTimer.GetDurationInSecs();

            minorCounter = 0;


            if ( majorCounter == majorCycle )
            {
                double dl = 0;
                double tm = 0;

                for ( int i = 0; i < majorCycle ; i++ )
                {
                    dl += blockDL[i];
                    tm += blockTime[i];
                }

                dl = dl/(majorCycle+1);

                tm = tm/(majorCycle+1);

                double currentDownloadSpeed = dl / tm;

                /* download speed - divide by 1024 to get speed in kilobytes instead of bytes */
                double idownloadSpeed = currentDownloadSpeed / 1024;

                string post;
                if ( idownloadSpeed > 1024 )
                {
                       idownloadSpeed = idownloadSpeed / 1024;
                       post = " MB/s";
                }
                else
                {
                        post = " KB/s";
                }

                string downloadSpeed = DoubleToString( idownloadSpeed );

                size_t x = downloadSpeed.find( "." );
                downloadSpeed.erase( x+2 );

                downSize = "Download Speed:  " + downloadSpeed + post;
                SendMessage( hDownloadSpeedSTATIC, WM_SETTEXT, (WPARAM)0, (LPARAM)downSize.c_str() );

                majorCounter = 0;
            }
            else
            {
                majorCounter++;
            }

            oldDownloadNow = dlnow;
            myTimer.Start();
    }
    else
    {
            minorCounter++;
    }

    return 0;
}
int minorCounter=0;
int majorCounter=0;
int最小循环=4;
int majorCycle=5;
双blockDL[6];
双阻塞时间[6];
int TraceProgress(void*clientp,双dltotal,双dlnow,双ultotal,双ulnow)
{
if(minorCounter==minorCycle)
{
blockDL[majorCounter]=dlnow-oldDownloadNow;
myTimer.Tick();
blockTime[MajoCounter]=myTimer.GetDurationInSecs();
最小计数=0;
如果(主循环==主循环)
{
双dl=0;
双tm=0;
for(int i=0;i1024)
{
idownloadSpeed=idownloadSpeed/1024;
post=“MB/s”;
}
其他的
{
post=“KB/s”;
}
字符串下载速度=DoubleToString(idownloadSpeed);
size\u t x=下载速度。查找(“.”);
下载速度。擦除(x+2);
downSize=“下载速度:”+downloadSpeed+post;
SendMessage(hDownloadSpeedSTATIC,WM_SETTEXT,(WPARAM)0,(LPARAM)downSize.c_str());
majorCounter=0;
}
其他的
{
MajoCounter++;
}
oldDownloadNow=dlnow;
myTimer.Start();
}
其他的
{
minorCounter++;
}
返回0;
}

您需要使用采样窗口和指数衰减或其他合理的方法

如果每30分钟就有一辆汽车从装配线上下来,而你只取一个样品,那么可怕的事情就会发生。例如,如果你在一辆车下线后取样,20分钟后再取样,你会在20分钟内看到零辆车,即每小时零辆车。如果你在一辆车下线前取样,31分钟后再取样,你会在31分钟内看到两辆车,每小时3.9辆

这里有一个简单的算法:

  • 保持单个计数和单个平均速度。从零开始

  • 每秒钟更新一次

  • 每秒,首先将前一秒接收的字节数添加到计数中

  • 将计数相加后,从计数中减去1/8的计数<代码>计数-=(计数/8)

  • 将平滑后的平均速度(以每秒为单位)更新为当前计数<代码>比特/秒=计数


  • 要了解此算法的工作原理,请假设计数为常量。这意味着加到计数上的金额必须等于减去的金额。这意味着计数必须是每秒添加的字节数的8倍,使其成为每秒接收的位数。

    可能测量时间太短。我猜,过去30秒左右的移动平均线会平滑变化,仍然显示合理的当前数据。@JerryCoffin是的,我真傻,没有正确理解场景,我已经更改了上面的代码,你怎么看?当然看起来更接近了。是的,鉴于调用回调的速度参差不齐,很难让事情顺利进行。@JerryCoffin有什么关于如何改进它的意见吗?我已经更改了上面的代码,你能看一看,让我知道它是否更好吗?如果你不能确保函数以相等的间隔被调用,您可以只跟踪上次执行
    count-=(count/8)的时间。如果过了不到一秒钟,不要这样做。如果超过两秒钟,则重复两次或更多次。