5

何千ものファイルをダウンロードする長いループを実行しています。何時間もかかる可能性があるため、推定残り時間を表示したいと思います。ただし、私が書いたものでは、平均ミリ秒数が得られます。この平均ダウンロード時間をミリ秒から に変換するにはどうすればよいTDateTimeですか?

私が設定している場所を見てくださいLabel1.Caption

procedure DoWork;
const
  AVG_BASE = 20; //recent files to record for average, could be tweaked
var
  Avg: TStringList; //for calculating average
  X, Y: Integer; //loop iterators
  TS, TE: DWORD; //tick counts
  A: Integer; //for calculating average
begin
  Avg:= TStringList.Create;
  try
    for X:= 0 to FilesToDownload.Count - 1 do begin //iterate through downloads
      if FStopDownload then Break; //for cancelling
      if Avg.Count >= AVG_BASE then //if list count is 20
        Avg.Delete(0); //remove the oldest average
      TS:= GetTickCount; //get time started
      try
        DownloadTheFile(X); //actual file download process
      finally
        TE:= GetTickCount - TS; //get time elapsed
      end;
      Avg.Add(IntToStr(TE)); //add download time to average list
      A:= 0; //reset average to 0
      for Y:= 0 to Avg.Count - 1 do //iterate through average list
        A:= A + StrToIntDef(Avg[Y], 0); //add to total download time
      A:= A div Avg.Count; //divide count to get average download time
      Label1.Caption:= IntToStr(A); //<-- How to convert to TDateTime?
    end;
  finally
    Avg.Free;
  end;
end;

PS - 最後の 20 回 (または AVG_BASE) のダウンロードの平均速度を計算するさまざまな方法を受け入れます。その間に速度が変化する可能性があるため、すべてのダウンロードに基づいて計算したくありません。したがって、私は最後の20件だけをチェックしています。

4

2 に答える 2

11

TDateTime 値は基本的に ですdouble。整数部分は日数で、端数は時間です。

1 日は 24*60*60 = 86400 秒 (SysUtils で宣言された SecsPerDay 定数) なので、TDateTime として A を取得するには:

dt := A/(SecsPerDay*1000.0); // A is the number of milliseconds 

時間を計測するためのより良い方法TStopWatchは、 unit で構文を使用することDiagnosticsです。

例:

sw.Create;
.. 
sw.Start;
// Do something
sw.Stop;
A := sw.ElapsedMilliSeconds;
// or as RRUZ suggested ts := sw.Elapsed; to get the TimeSpan 

平均時間を取得するには、次のmoving averageレコードを使用することを検討してください。

Type
  TMovingAverage = record
  private
    FData: array of integer;
    FSum: integer;
    FCurrentAverage: integer;
    FAddIx: integer;
    FAddedValues: integer;
  public
    constructor Create(length: integer);
    procedure Add( newValue: integer);
    function Average : Integer;
  end;

procedure TMovingAverage.Add(newValue: integer);
var i : integer;
begin
  FSum := FSum + newValue - FData[FAddIx];
  FData[FAddIx] := newValue;
  FAddIx := (FAddIx + 1) mod Length(FData);
  if (FAddedValues < Length(FData)) then
    Inc(FAddedValues);
  FCurrentAverage := FSum div FAddedValues;
end;

function TMovingAverage.Average: Integer;
begin
  Result := FCurrentAverage;
end;

constructor TMovingAverage.Create(length: integer);
var
  i : integer;
begin
  SetLength( FData,length);
  for i := 0 to length - 1 do
    FData[i] := 0;
  FSum := 0;
  FCurrentAverage := 0;
  FAddIx := 0;
  FAddedValues := 0;
end;
于 2012-08-27T05:19:03.167 に答える
8

TDateTimeの代わりに、レコードを使用できます。コンストラクターTTimeSpanに経過したティックを渡す新しいインスタンスを作成できます。ここから、Days、Hours、minutes、seconds、およびMillisecondsプロパティを使用して経過時間を表示できます。次に、残り時間を計算するために、ダウンロードする合計バイト数と現在ダウンロードされているバイト数が必要です。

于 2012-08-27T03:03:35.013 に答える