Delphi中上传速度问题的计算

Delphi中上传速度问题的计算,delphi,file-upload,Delphi,File Upload,我使用Delphi2010和聪明的internet suite组件上传文件,并想计算上传速度 我试过这个代码,但它给了我“INF”在标签+错误的速度 那代码有什么问题 private FBytesProceed : Int64; FTimeStamp : TDateTime; FSpeed : double; end; procedure TForm2.clHttp1SendProgress(Sender: TObject; ABytesProceed, ATotalBytes

我使用Delphi2010和聪明的internet suite组件上传文件,并想计算上传速度

我试过这个代码,但它给了我“INF”在标签+错误的速度

那代码有什么问题

private
  FBytesProceed : Int64;
  FTimeStamp : TDateTime;
  FSpeed : double;
end;

procedure TForm2.clHttp1SendProgress(Sender: TObject; ABytesProceed,
  ATotalBytes: Int64);
var
  LTimeStamp : TDateTime;
begin
  LTimeStamp := Now;
  if FBytesProceed < ABytesProceed then
  begin
    // calculating bytes per second
    FSpeed := ( ABytesProceed - FBytesProceed ) {bytes}
            / ( ( LTimeStamp - FTimeStamp ) {days}
              * 24 {hours}
              * 60 {minutes}
              * 60 {seconds} );
  end;
  FBytesProceed := ABytesProceed;
  FTimeStamp := LTimeStamp;

label1.Caption  := Format(' speed %n Kbps',[FSpeed / 1024]);

end;
private
fBytes进程:Int64;
FTimeStamp:TDateTime;
FSpeed:double;
结束;
程序TForm2.CLHTTP1SENDPROCESS(发送方:TObject;ABYTESPROCED,
原子字节:Int64);
变量
LTimeStamp:TDateTime;
开始
LTimeStamp:=现在;
如果fBytes进程
正如您所遇到的,系统计时器的分辨率不是很好。我似乎记得它可以低至50毫秒。有两种方法可以解决这个问题,其中一些取决于程序的结构

第一,你可以使用一个常规的TTimer设置为2秒或任何你想要的时间间隔。每次触发时,您都会获得字节计数,将其与上次触发计时事件的时间进行比较,并使用上载速率设置标题。这显然只有在处理非阻塞上传时才起作用。如果你不想使用TTimer,你也可以在一个单独的线程中这样做,让它每隔几秒钟检查一次上传

另一种方法是继续做你正在做的事情,但只在一秒钟后更新上传速率。我建议使用GetTickCount()而不是Now()(因为您实际上不需要日期,只需要一个计数器)。GetTickCount()返回表示毫秒的整数,而不是浮点值。从0开始字节计数。对于上载的每个块,将该数量添加到字节计数中。然后检查滴答数。如果自上次标题更新后已过了一秒钟,则更新标题并将字节计数设置回零,并记录下一次上传区块时的刻度计数

(只是一些伪代码来说明我在第二个选项中所说的内容)

“现在”不是一个好的计时器。像GetTickCount这样的东西更准确。GetTickCount非常有用,因为它提供了一个自系统启动以来的毫秒值,并且速度非常快。最好看更长的一段时间。不久前我做过类似的事情,如果你不使用某种窗口,你的速度最终会在整个节目中嘎嘎作响。我发现最好保留最后的x个值,然后用它们来计算性能。它为用户提供了更流畅的反馈

例如,类似这样的操作应该有效(使用10个值):

类型
TDataBlock=记录
数据传输:Int64;
蒂梅尔蒂克:红衣主教;
结束;
TForm2=类别(TForm)
...
私有的
FBlocks:TList;
FLastAmount:整数;
FpPreviousProceduce:Int64;
FPreviousTickCount:基数;
...
结束;
程序TForm2.CLHTTP1SENDPROCESS(发送方:TObject;ABYTESPROCED,
原子字节:Int64);
变量
支票:红衣主教;
数据块:TDataBlock;
速度:Int64;
红衣主教;
TotalData:Int64;
开始
CheckTickCount:=GetTickCount;
DataBlock.datatransfer:=ABytesProceed-fpreviousproced;
DataBlock.TimerTick:=CheckTickCount-FPreviousTickCount;
添加(数据块);
如果FBlocks.Count>10,则
FBlocks.Delete(0);//确保我们的窗口保持在最后10个值
TotalTicks:=0;
总数据:=0;
对于FBlocks中的数据块,请执行以下操作:
开始
TotalTicks:=TotalTicks+DataBlock.TimerTick;
TotalData:=TotalData+DataBlock.DataTransfer;
结束;
//每秒计算字节数
速度:=TotalData{bytes}*1000 div TotalTicks{ms};
标签1.标题:=格式('speed%n Kbps',[speed/1024]);
fpreviousprocedure:=abytesproced;
FPreviousTickCount:=CheckTickCount;
结束;

在开始之前,您显然需要创建列表并初始化所有变量。

如果LTimeStamp=FTimeStamp,您将得到一个被零除的错误。但这应该很容易通过调试器跟踪。在将FSpeed指定给标题之前,请先查看它。请记住,由于您使用的是“now”,Windows中默认计时器的分辨率不是很高,因此如果在紧密循环中调用,您可能会得到相同的结果。您是对的,LTimeStamp=FTimeStamp这就是问题所在,老实说,我不知道如何解决该问题或编写任何替代方案?有什么建议吗?Diagnostics.TStopwatch是我们需要的,而不是GetTickCount+1解决这个问题的正确方法是减少更新频率,并在更长的范围内计算下载速度。我可能每2-5秒更新一次,但计算的时间间隔可能更长。
t := GetTickCount();
n := t - LastTick;
if (n > 2000) then  //2 seconds
begin
    rate := ByteCount / n;

    caption := format(....);

    LastTick := t;
    ByteCount := 0;     
end;
type
  TDataBlock = record
    DataTransferred: Int64;
    TimerTick: Cardinal;
  end;

  TForm2 = class(TForm)
    ...
  private
    FBlocks: TList<TDataBlock>;
    FLastAmount: Integer;
    FPreviousProceed: Int64;
    FPreviousTickCount: Cardinal;
    ...
  end;

  procedure TForm2.clHttp1SendProgress(Sender: TObject; ABytesProceed,
      ATotalBytes: Int64);
  var
    CheckTickCount: Cardinal;
    DataBlock: TDataBlock;
    Speed: Int64;
    TotalTicks: Cardinal;
    TotalData: Int64;
  begin
    CheckTickCount := GetTickCount;
    DataBlock.DataTransferred := ABytesProceed - FPreviousProceed;
    DataBlock.TimerTick := CheckTickCount - FPreviousTickCount;
    FBlocks.Add(DataBlock);
    if FBlocks.Count > 10 then
      FBlocks.Delete(0); // Make sure we keep our window at the last 10 values

    TotalTicks := 0;
    TotalData := 0;
    for DataBlock in FBlocks do
    begin
      TotalTicks := TotalTicks + DataBlock.TimerTick;
      TotalData := TotalData + DataBlock.DataTransferred;
    end;

    // calculating bytes per second
    Speed := TotalData {bytes} * 1000 div TotalTicks {ms};

    label1.Caption  := Format(' speed %n Kbps',[Speed / 1024]);
    FPreviousProceed := ABytesProceed;
    FPreviousTickCount := CheckTickCount;
  end;