Передача файлов Indy10 вызывает 100% загрузку процессора - PullRequest
3 голосов
/ 14 ноября 2010

Мне удалось исправить некоторые ошибки с отключением, теперь, когда файл передается, загрузка ЦП становится 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 ]

6 голосов
/ 14 ноября 2010

избавиться от Application.ProcessMessages;он НЕ ДОЛЖЕН вызываться в потоке, отличном от основного

4 голосов
/ 14 ноября 2010

Вы вызываете Application.ProcessMessages в цикле приема, по-видимому, для того, чтобы остальная часть вашего приложения не зависла.Использование процессора на 100% является побочным эффектом.

Вам лучше использовать компонент IdAntiFreeze (все еще разновидность хака) или поместить функциональность ReceiveData в поток.

Обновление:

Упс.На первый взгляд, я думал, что это передача на стороне клиента, выполняющаяся в основном потоке, но на самом деле она вызывается в отдельном потоке IdTcpServer.В этом случае совет APZ28 является правильным;не вызывайте Application.ProcessMessages в потоке.

2 голосов
/ 15 ноября 2010

Я ничего не знаю об Indy (я использую свой собственный модуль, который легче / быстрее, чем Indy, для всех вещей клиент / сервер TCP / IP - см. http://synopse.info),, но я предполагаю, что ваш метод IdTCPServer1Execute должен работать в фоновом потоке, что здесь не так.

Итак:

  1. Избавьтесь от всех этих Application.ProcessMessages и подобных;
  2. Используйте таймер для синхронизации вашего пользовательского интерфейса (достаточно обновить одну секунду, считывая количество переданных байтов), а не метод Notify () или Synchronize ();
  3. Убедитесь, что ваш компонент IdTCPServer1 работает в отдельном потоке (для этого должно быть какое-то свойство);
  4. Другая возможность (очень маловероятная) заключается в том, что метод ReadStream не нужно вызывать как таковой, и он не ожидает данных с точки зрения загрузки процессора; в этом случае Indy должен предоставить некоторый метод для ожидания ожидающих данных без блокировки.
  5. Используйте профилировщик (есть несколько бесплатных - например, http://delphitools.info), чтобы угадать, где ваш процессор сгорел.
  6. Запуск за пределами IDE - это то же самое поведение?
1 голос
/ 18 ноября 2010

Вы и я обсуждали эту тему на форумах Embarcadero ( кэшируется на CodeNewsFast ).

1 голос
/ 14 ноября 2010

Ваш цикл постоянно, простой способ - добавить Sleep(1) после вашего Application.ProcessMessages.

Но, возможно, вы могли бы изменить порядок своего кода, чтобы заблокировать функцию ReadStream, и запускать только тогда, когда получено разумное количество данных или истекло время ожидания.

...