开发者

Indy10 File Transfer Causes 100% CPU Usage

i managed to fix some errors with disconnecting, now whenever a file is transferring the CPU Usage becomes 100%, i dunno what im doing wrong :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;
  Clien开发者_Go百科t.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;


Get rid of Application.ProcessMessages; it MUST NOT be called under thread other than main one


You're calling Application.ProcessMessages in your receive loop, presumably to keep the rest of your application from appearing to be frozen. The 100% CPU usage is a side effect.

You're better off using an IdAntiFreeze component (still kind of a hack) or putting the ReceiveData functionality in a thread.

Update:

Whoops. At first glance, I thought this was a client side transfer running in the main thread, but it's actually being called in a separate IdTcpServer thread. In this case, APZ28's advice is correct; don't call Application.ProcessMessages in a thread.


I dont' know anything about Indy (I use my own unit, which is lighter/faster than Indy, for all TCP/IP client/server stuff - see http://synopse.info), but I guess your IdTCPServer1Execute method should run in a background thread, which is not the case here.

So :

  1. Get rid of all those Application.ProcessMessages and such;
  2. Use a timer to synchronize your UI (a one second refresh reading the transferred byte count is enough), and not a Notify() nor Synchronize() method;
  3. Ensure that your IdTCPServer1 component is running in a separate thread (there should be some property to do that);
  4. Another possibility (very unlikely) is that the ReadStream method don't have to be called as such, and don't wait for data in a CPU-friendly way; if it's the case, there should be some method made available by Indy to wait for pending data, without blocking.
  5. Use a profiler (there are some free one around - like http://delphitools.info ) to guess where your CPU is burnt.
  6. Run outside the IDE - is it the same behavior?


Your looping constantly, an easy hack is to add an Sleep(1) after your Application.ProcessMessages.

But perhaps you could reorder your code to block on the ReadStream function, and only run when a reasonable amount of data is received, or a timeout has passed.


You and I covered this topic in the Embarcadero forums (cached on CodeNewsFast).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜