Delphi中上传速度问题的计算
我使用Delphi2010和聪明的internet suite组件上传文件,并想计算上传速度 我试过这个代码,但它给了我“INF”在标签+错误的速度 那代码有什么问题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
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;