Delphi RIO - Indy TCPServer 高 CPU 使用率
Delphi RIO - Indy TCPServer high CPU usage
我在Delphi RIO + Indy TCP Server 中开发了一个简单的TCP 文件服务器程序。当 2 个或更多客户端请求文件时,CPU 在 90 年代运行非常高。这吓坏了服务器团队,在此期间,他们很难登录程序所在的服务器 运行。
根据有关该主题的其他线程,当我放置 IndySleep(x) 时,它确实降低了 CPU 并且平均时间保持在 50-60 秒。我知道放置 IndySleep() 可能会有点节流,但它确实有效!
它提供的文件已经压缩,大小从 1KB 到 <10MB 不等。
我还能做些什么来提高整体 CPU 使用率,无论有没有 IndySleep() 或很少 IndySleep()?
这是代码片段:
procedure TMainForm.IdTCPSyncServerExecute(AContext: TIdContext);
begin
if (not AContext.Connection.IOHandler.InputBufferIsEmpty)
and (AContext.Connection.Connected) then
begin
SendFile(AContext, AContext.Connection.IOHandler.ReadLn);
//IndySleep(1000 div IdTCPSyncServer.Contexts.Count); // For high CPU
IndySleep(500); // For high CPU
end;
end;
procedure TMainForm.SendFile(AContext: TIdContext; AFileName: string);
var
lStream: TFileStream;
begin
lStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
if Assigned(lStream) then
begin
try
WriteRespHeader(AContext, 1, lStream.Size); //Custom fn() writes back to client file size and other useful info
AContext.Connection.IOHandler.LargeStream := False; // 32-bit
lStream.Position := 0;
AContext.Connection.IOHandler.Write(lStream, lStream.Size);
finally
lStream.Free;
end;
AddLogMsg(AContext.Binding.PeerIP + ' : Sent File: ' + AFileName); // Thread.Queue() based logging
end;
end;
您在错误的地方调用了 IndySleep()
。如果客户端还没有任何内容可供阅读,您将立即退出 OnExecute
并立即返回,从而形成一个紧密的循环。这就是您的高 CPU 使用率可能发生的地方。只有在没有可用的时候才休眠,例如:
procedure TMainForm.IdTCPSyncServerExecute(AContext: TIdContext);
begin
if (not AContext.Connection.IOHandler.InputBufferIsEmpty)
and (AContext.Connection.Connected) then
begin
SendFile(AContext, AContext.Connection.IOHandler.ReadLn);
end else begin
//IndySleep(1000 div IdTCPSyncServer.Contexts.Count); // For high CPU
IndySleep(500); // For high CPU
// or, use AContext.Connection.IOHandler.Readable() instead...
// or, use AContext.Connection.IOHandler.CheckForDataOnSoure() instead...
end;
end;
或者,我通常建议使用这种手动检查:
procedure TMainForm.IdTCPSyncServerExecute(AContext: TIdContext);
begin
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.CheckForDataOnSource(500{1000 div IdTCPSyncServer.Contexts.Count}); // For high CPU
AContext.Connection.IOHandler.CheckForDisconnect;
if AContext.Connection.IOHandler.InputBufferIsEmpty then Exit;
end;
SendFile(AContext, AContext.Connection.IOHandler.ReadLn);
end;
但实际上,在这种情况下,更好的解决方案是完全不手动检查客户端数据是否存在。如果还没有什么可读的,就让 IOHandler.ReadLn()
阻塞直到有东西真正到达,例如:
procedure TMainForm.IdTCPSyncServerExecute(AContext: TIdContext);
begin
SendFile(AContext, AContext.Connection.IOHandler.ReadLn);
end;
我在Delphi RIO + Indy TCP Server 中开发了一个简单的TCP 文件服务器程序。当 2 个或更多客户端请求文件时,CPU 在 90 年代运行非常高。这吓坏了服务器团队,在此期间,他们很难登录程序所在的服务器 运行。
根据有关该主题的其他线程,当我放置 IndySleep(x) 时,它确实降低了 CPU 并且平均时间保持在 50-60 秒。我知道放置 IndySleep() 可能会有点节流,但它确实有效!
它提供的文件已经压缩,大小从 1KB 到 <10MB 不等。
我还能做些什么来提高整体 CPU 使用率,无论有没有 IndySleep() 或很少 IndySleep()?
这是代码片段:
procedure TMainForm.IdTCPSyncServerExecute(AContext: TIdContext);
begin
if (not AContext.Connection.IOHandler.InputBufferIsEmpty)
and (AContext.Connection.Connected) then
begin
SendFile(AContext, AContext.Connection.IOHandler.ReadLn);
//IndySleep(1000 div IdTCPSyncServer.Contexts.Count); // For high CPU
IndySleep(500); // For high CPU
end;
end;
procedure TMainForm.SendFile(AContext: TIdContext; AFileName: string);
var
lStream: TFileStream;
begin
lStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
if Assigned(lStream) then
begin
try
WriteRespHeader(AContext, 1, lStream.Size); //Custom fn() writes back to client file size and other useful info
AContext.Connection.IOHandler.LargeStream := False; // 32-bit
lStream.Position := 0;
AContext.Connection.IOHandler.Write(lStream, lStream.Size);
finally
lStream.Free;
end;
AddLogMsg(AContext.Binding.PeerIP + ' : Sent File: ' + AFileName); // Thread.Queue() based logging
end;
end;
您在错误的地方调用了 IndySleep()
。如果客户端还没有任何内容可供阅读,您将立即退出 OnExecute
并立即返回,从而形成一个紧密的循环。这就是您的高 CPU 使用率可能发生的地方。只有在没有可用的时候才休眠,例如:
procedure TMainForm.IdTCPSyncServerExecute(AContext: TIdContext);
begin
if (not AContext.Connection.IOHandler.InputBufferIsEmpty)
and (AContext.Connection.Connected) then
begin
SendFile(AContext, AContext.Connection.IOHandler.ReadLn);
end else begin
//IndySleep(1000 div IdTCPSyncServer.Contexts.Count); // For high CPU
IndySleep(500); // For high CPU
// or, use AContext.Connection.IOHandler.Readable() instead...
// or, use AContext.Connection.IOHandler.CheckForDataOnSoure() instead...
end;
end;
或者,我通常建议使用这种手动检查:
procedure TMainForm.IdTCPSyncServerExecute(AContext: TIdContext);
begin
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.CheckForDataOnSource(500{1000 div IdTCPSyncServer.Contexts.Count}); // For high CPU
AContext.Connection.IOHandler.CheckForDisconnect;
if AContext.Connection.IOHandler.InputBufferIsEmpty then Exit;
end;
SendFile(AContext, AContext.Connection.IOHandler.ReadLn);
end;
但实际上,在这种情况下,更好的解决方案是完全不手动检查客户端数据是否存在。如果还没有什么可读的,就让 IOHandler.ReadLn()
阻塞直到有东西真正到达,例如:
procedure TMainForm.IdTCPSyncServerExecute(AContext: TIdContext);
begin
SendFile(AContext, AContext.Connection.IOHandler.ReadLn);
end;