起步软件技术论坛-X3

 找回密码
 立即注册
搜索
查看: 233|回复: 2

[分享]大量循环时候的代码优化**

[复制链接]
发表于 2007-11-21 10:26:38 | 显示全部楼层 |阅读模式
1  如果有大量的循环,那么尽量减少循环中调用函数,而是把函数结果记录下来,然后在循环中直接使用。
比如下面第一个函数 ShowMemoResult 在循环中多次调用 GetFieldSize 函数
第二个函数 ShowMemoResult1 则声明一个数组,在数组中记录了字段的长度,循环中使用这个数组,而不是调用这个函数
function GetFieldSize(AField: TDataField): Integer;
begin
  case AField.DataType of
    TFieldType.ftBoolean:
        Result := 20;
    TFieldType.ftDate, TFieldType.ftDateTime, TFieldType.ftTime:
        Result := 20;
    TFieldType.ftInteger, TFieldType.ftLargeint, TFieldType.ftSmallint:
        Result := 20;
    TFieldType.ftFloat:
        Result := 20;
    else
        Result := AField.Size;
  end;
  if Result<Length(AField.FieldName) then Result := Length(AField.FieldName);
end;

procedure TMainForm.ShowMemoResult(ADataSet: TClientDataSet);
var
  i: Integer;
  s: String;
  sValue: String;
begin
  memResult.Lines.BeginUpdate;
  try
    memResult.Clear;

    s := '';
    for i:=0 to ADataSet.FieldCount-1 do
    begin
      sValue := ADataSet.Fields.FieldName;
      sValue := sValue+StrUtils.DupeString(' ', GetFieldSize(ADataSet.Fields)-Length(sValue));
      s := s+sValue+' ';
    end;
    memResult.Lines.Add(s);

    s := '';
    for i:=0 to ADataSet.FieldCount-1 do
    begin
      sValue := StrUtils.DupeString('-', GetFieldSize(ADataSet.Fields));
      s := s+sValue+' ';
    end;
    memResult.Lines.Add(s);

    ADataSet.First;
    while not ADataSet.Eof do
    begin
      s := '';
      for i:=0 to ADataSet.FieldCount-1 do
      begin
        sValue := ADataSet.Fields.AsString;
        sValue := sValue+StrUtils.DupeString(' ', GetFieldSize(ADataSet.Fields)-Length(sValue));
        s := s+ sValue +' ';
      end;
      memResult.Lines.Add(s);
      ADataSet.Next;
    end;

    memResult.Lines.Add('--------------------');
    memResult.Lines.Add(SysUtils.IntToStr(ADataSet.RecordCount)+' Results');
  finally
    memResult.Lines.EndUpdate;
  end;
end;

procedure TMainForm.ShowMemoResult1(ADataSet: TClientDataSet);
var
  i: Integer;
  s: String;
  sValue: String;
  lSize: array of Integer;
begin
  memResult.Lines.BeginUpdate;
  try
    memResult.Clear;

    SetLength(lSize, ADataSet.FieldCount);
    s := '';
    for i:=0 to ADataSet.FieldCount-1 do
    begin
      lSize := GetFieldSize(ADataSet.Fields);
      sValue := ADataSet.Fields.FieldName;
      sValue := sValue+StrUtils.DupeString(' ', lSize-Length(sValue));
      s := s+sValue+' ';
    end;
    memResult.Lines.Add(s);

    s := '';
    for i:=0 to ADataSet.FieldCount-1 do
    begin
      sValue := StrUtils.DupeString('-', lSize);
      s := s+sValue+' ';
    end;
    memResult.Lines.Add(s);

    ADataSet.First;
    while not ADataSet.Eof do
    begin
      s := '';
      for i:=0 to ADataSet.FieldCount-1 do
      begin
        sValue := ADataSet.Fields.AsString;
        sValue := sValue+StrUtils.DupeString(' ', lSize-Length(sValue));
        s := s+ sValue +' ';
      end;
      memResult.Lines.Add(s);
      ADataSet.Next;
    end;

    memResult.Lines.Add('--------------------');
    memResult.Lines.Add(SysUtils.IntToStr(ADataSet.RecordCount)+' Results');
  finally
    SetLength(lSize, 0);
    memResult.Lines.EndUpdate;
  end;
end;

procedure TMainForm.actSpeedTestExecute(Sender: TObject);
var
  lStart, lEnd: Integer;
begin
  Query1.Open;
  lStart := Borland.Delphi.Windows.GetTickCount;
  ShowMemoResult(TClientDataSet(Query1));
  lEnd := Borland.Delphi.Windows.GetTickCount;
  Caption := SysUtils.IntToStr(lEnd-lStart);

  lStart := Borland.Delphi.Windows.GetTickCount;
  ShowMemoResult1(TClientDataSet(Query1));
  lEnd := Borland.Delphi.Windows.GetTickCount;
  Caption := '1:'+Caption +' 2:'+ SysUtils.IntToStr(lEnd-lStart);
end;

这里要注意不同的数据量下,两个函数的性能不一样的
585条记录时候
第一个函数用时  2000毫秒   第二个函数用时 3400毫秒
2829条记录时候
第一个函数用时  5500毫秒   第二个函数用时 1800毫秒
9717条记录时候
第一个函数出错Heap error   第二个函数用时 121000毫秒

因为结果都输出到Memo中,因此当数据量太大时候会出错,如果不输出Memo也可以出结果,但是肯定比第二个函数性能要差很多
回复

使用道具 举报

 楼主| 发表于 2007-12-3 15:29:19 | 显示全部楼层
能用for的尽量for,而不是用while
procedure TMainForm.Button1Click(Sender: TObject);
var
  i: Integer;
  iCnt: Integer;
  iTicks, iWhile, iFor: Integer;
begin
  iCnt := SysUtils.StrToInt(edtCnt.Text);
  Memo1.Lines.Add('');
  Memo1.Lines.Add('循环'+edtCnt.Text+'次比较');

  iTicks := Borland.Delphi.Windows.GetTickCount;
  i:=0;
  while i<iCnt do
  begin
    Inc(i);
    //i := i+1;
  end;
  iWhile := Borland.Delphi.Windows.GetTickCount-iTicks;
  Memo1.Lines.Add('while用时:'+SysUtils.IntToStr(iWhile));

  iTicks := Borland.Delphi.Windows.GetTickCount;
  for i:=0 to iCnt-1 do
    ;
  iFor := Borland.Delphi.Windows.GetTickCount-iTicks;
  Memo1.Lines.Add('  for用时:'+SysUtils.IntToStr(iFor));
  Memo1.Lines.Add(SysUtils.Format('性能差距:%4.2f%%', [(iWhile-iFor)/iFor*100]));
end;

循环900000次比较
while用时:1422
  for用时:1000
性能差距:42.20%

循环9000000次比较
while用时:14078
  for用时:9938
性能差距:41.66%

循环9000000次比较
while用时:13953
  for用时:10391
性能差距:34.28%
回复 支持 反对

使用道具 举报

 楼主| 发表于 2007-12-4 09:50:56 | 显示全部楼层
Delphi的帮助中说用Inc比直接加速度要快
var

  IntVar: Integer;
  LongintVar: Longint;
begin
  Inc(IntVar);                { IntVar := IntVar + 1 }
  Inc(LongintVar, 5);        { LongintVar := LongintVar + 5 }
end;

但是我在X3平台上,在Delphi中都做了测试,反而是Inc会慢
var
  i: Integer;
  iCnt: Integer;
  iTicks, iAdd, iInc: Integer;
  iTest: Integer;
begin
  iCnt := SysUtils.StrToInt(edtCnt.Text);
  Memo1.Lines.Add('');
  Memo1.Lines.Add('循环'+edtCnt.Text+'次比较');

  iTicks := Borland.Delphi.Windows.GetTickCount;
  iTest := 0;
  for i:=0 to iCnt-1 do
    iTest := iTest+2;
  iAdd := Borland.Delphi.Windows.GetTickCount-iTicks;
  Memo1.Lines.Add('Add用时:'+SysUtils.IntToStr(iAdd));

  iTicks := Borland.Delphi.Windows.GetTickCount;
  iTest := 0;
  for i:=0 to iCnt-1 do
    Inc(iTest, 2);
  iInc := Borland.Delphi.Windows.GetTickCount-iTicks;
  Memo1.Lines.Add('Inc用时:'+SysUtils.IntToStr(iInc));
  Memo1.Lines.Add(SysUtils.Format('性能差距:%4.2f%%', [(iAdd-iInc)/iInc*100]));
end;


循环1000次比较
Add用时:0
Inc用时:0

循环10000次比较
Add用时:16
Inc用时:31
性能差距:-48.39%

循环100000次比较
Add用时:187
Inc用时:235
性能差距:-20.43%

循环1000000次比较
Add用时:1953
Inc用时:2375
性能差距:-17.77%

循环10000000次比较
Add用时:20141
Inc用时:25500
性能差距:-21.02%
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Justep Inc.

GMT+8, 2025-7-1 11:00 , Processed in 0.044551 second(s), 15 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表