Indy10文件传输导致100%的CPU使用率

时间:2010-11-14 12:21:32

标签: delphi delphi-7 indy10

我设法通过断开连接修复了一些错误,现在每当文件传输CPU使用率变为100%时,我不知道我做错了什么:S .....

const
 MaxBufferSize = 1024;

type
 TClient = class(TObject)
 public
  AContext: TIdContext;
  FileSize: Integer;
  Canceled: Boolean;
  Transfered: Integer;
  procedure ReceiveData;
  procedure Update;
 end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
 Data: string;
 Client: TClient;
 Item: TListItem;
begin
 Data := AContext.Connection.IOHandler.ReadLn;

 //Data := 'SEND|785548' = Command + | + FileSize
 if Copy(Data, 1, 4) = 'SEND' then
 begin
  Delete(Data, 1, 5);
  Client := TClient.Create;
  Client.FileSize := StrToInt(Data);
  Client.AContext := AContext;
  Item := ListView1.Items.Add;
  Item.Caption := AContext.Connection.Socket.Binding.PeerIP;
  Item.Data := Client;
  Client.ReceiveData;
 end;
end;

procedure TClient.ReceiveData;
var
 currRead : Integer;
 FS: TFileStream;
begin
 Canceled := False;
 FS := TFileStream.Create('C:\Test.dat', fmCreate or fmOpenReadWrite);
 FS.Size := 0;
 Transfered := 0;
 try
  while (FS.Position < FileSize) and (Athread.Connection.Connected) and (not Canceled) do
  begin
   Application.ProcessMessages;
   if (FileSize - FS.Position) >= MaxBufferSize then currRead := MaxBufferSize
   else currRead := (FileSize - FS.Position);
   AThread.Connection.IOHandler.ReadStream(FS, CurrRead);
   Transfered := FS.Position;
   Notify.NotifyMethod(Update);
   Application.ProcessMessages;
  end;
 finally
  FS.Free;
  AThread.Connection.IOHandler.InputBuffer.Clear;
  AThread.Connection.Disconnect;
  AThread.RemoveFromList;
  Notify.NotifyMethod(Update);
  Application.ProcessMessages;
 end;
end;

procedure TClient.Update;
begin
 //Code to Display Progress bar and stuff (Simplified for now)
 Form1.Label1.Caption := 'Transfered Data : ' + IntToStr(Transfered);
end;

5 个答案:

答案 0 :(得分:6)

摆脱Application.ProcessMessages;它绝不能在主线程之外的线程下调用

答案 1 :(得分:4)

您在接收循环中调用Application.ProcessMessages,可能是为了防止应用程序的其余部分被冻结。 100%的CPU使用率是副作用。

最好使用IdAntiFreeze组件(仍然是一种黑客攻击)或将ReceiveData功能放在一个线程中。

更新

糟糕。乍一看,我认为这是在主线程中运行的客户端传输,但它实际上是在一个单独的IdTcpServer线程中调用的。在这种情况下,APZ28的建议是正确的;不要在一个线程中调用Application.ProcessMessages。

答案 2 :(得分:2)

我对Indy一无所知(我使用自己的单位,比Indy更轻/更快,对于所有TCP / IP客户端/服务器的东西 - 请参阅http://synopse.info),但我想你的IdTCPServer1Execute方法应该在后台线程中运行,这不是这里的情况。

所以:

  1. 摆脱所有Application.ProcessMessages等;
  2. 使用计时器同步您的UI(读取传输的字节数一秒刷新就足够了),而不是Notify()和Synchronize()方法;
  3. 确保您的IdTCPServer1组件在单独的线程中运行(应该有一些属性可以执行此操作);
  4. 另一种可能性(非常不可能)是不必像这样调用ReadStream方法,也不要以CPU友好的方式等待数据;如果是这种情况,Indy应该有一些方法可以等待未决数据而不会阻塞。
  5. 使用分析器(有一些免费的 - 如http://delphitools.info)来猜测你的CPU被烧毁的位置。
  6. 在IDE外部运行 - 它的行为是否相同?

答案 3 :(得分:1)

您的循环不断,一个简单的黑客就是在Sleep(1)之后添加Application.ProcessMessages

但也许您可以重新排序代码以阻止ReadStream函数,并且仅在收到合理数量的数据或超时时才运行。

答案 4 :(得分:1)

您和我在Embarcadero forumscached on CodeNewsFast)中介绍了此主题。