【问题标题】:Indy10 File Transfer Causes 100% CPU UsageIndy10 文件传输导致 100% CPU 使用率
【发布时间】:2010-11-14 12:21:31
【问题描述】:

我设法通过断开连接修复了一些错误,现在每当文件传输时 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;

【问题讨论】:

    标签: delphi delphi-7 indy10


    【解决方案1】:

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

    【讨论】:

    • 此外,摆脱 ListView1.Items.Add 调用;这是一个VCL方法,所以不能从VCL线程外调用。
    • 同样的效果,现在 CPU 使用率从 98% 到 100% 不等
    【解决方案2】:

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

    您最好使用 IdAntiFreeze 组件(仍然是一种 hack)或将 ReceiveData 功能放在线程中。

    更新:

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

    【讨论】:

      【解决方案3】:

      我对 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 之外运行 - 行为是否相同?

      【讨论】:

      • 我几乎尝试了所有方法,除了非阻塞流读取,我真的不知道该怎么做.....,知道它是怎么做的吗?谢谢回答
      • 好的,但是你的组件支持 unicode 吗?因为那是你首先要搬到 indy10
      • 当然,SynCrtUnit 可以工作,并且从 Delphi 6 到 Delphi XE 都经过测试。它使用 AnsiString 类型,您可以轻松地将其转换为 Unicode 字符串。
      【解决方案4】:

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

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

      【讨论】:

      • 它将 CPU 使用率降低到 90%,但现在传输速度要慢得多,我该如何做那个阻塞的事情?实际上客户端正在以 1024 字节块发送数据
      • 尝试删除所有Application.ProcessMessages,以及Notify.NotifyMethod(Update);
      • 所有 Application.ProcessMessages 被删除,并且在删除 Notify 后没有差异
      • 如果我没记错的话 Indy 可能无法使用 Indy 进行阻塞操作。所以您可以使用事件处理程序来处理新数据,如果您想要一个简单的循环,请使用概要,使用执行 tcp 协议(阻塞)的更酷的方法
      【解决方案5】:

      你和我在Embarcadero forums (cached on CodeNewsFast) 中讨论了这个话题。

      【讨论】:

      • 你会看一下吗? plunder.com/80961bd7e3 抱歉,如果它有一些错误,我正试图让它工作:(
      • 在论坛上:The specified thread [46075] was not found. 有人缓存过吗? (不在 web.archive.org 上)
      • Embarcadero 新闻组/论坛缓存在 codenewsfast
      猜你喜欢
      • 2019-01-14
      • 2015-04-05
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      • 2012-11-24
      • 2020-10-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多