[英]Delphi slow readln() after set memcashed value using TIdTCPClient
I have made a class TmemcacheClass where I can set and get values from memcached.我创建了一个类 TmemcacheClass,我可以在其中设置和从 memcached 获取值。
It's used in a Delphi Webbroker app, where each thread open TmemcacheClass and use it in its life.它用于 Delphi Webbroker 应用程序,其中每个线程打开 TmemcacheClass 并在其生命周期中使用它。 meaning every thread open TIdTCPClient, and connect it and reuse for every request.
意味着每个线程打开 TIdTCPClient,并连接它并为每个请求重用。
Get value are very speedy like 0 to 1 ms Set value are also speedy like 1 ms , but to wait for readln after set takes 47 ms.获取值非常快,如 0 到 1 ms 设置值也非常快,如 1 ms ,但在设置后等待 readln 需要 47 ms。
Any Idea how to speed this up.任何想法如何加快速度。
Is the procedure store() that are very slow waiting for是非常慢的等待过程 store()
line:= tcp.Socket.ReadLn();行:= tcp.Socket.ReadLn();
Adding hole unit, maybe I could drop the readln after save to speed it up ?添加孔单元,也许我可以在保存后删除 readln 以加快速度? If I drop readln I guess I need to clear socket since I am reusing same socket.
如果我删除 readln 我想我需要清除套接字,因为我正在重用相同的套接字。
unit unitMemcache;
interface
uses
system.sysutils,system.classes,system.JSON,idtcpclient,idGlobal;
type
TmemcacheClass = Class ( Tobject )
private
tcp : TIdTCPClient;
ConnectTimeout : integer;
Fconnected: Boolean;
Ferror: String;
Fcontent: String;
Flinecounter : Integer;
procedure Setconnected(const Value: Boolean);
procedure Seterror(const Value: String);
procedure reportError(e:string);
procedure Setcontent(const Value: String);
public
constructor create( ip : string ) ;
destructor Destroy ( ) ; override ;
procedure store(Key, Value: string);
function Lookup(Key: string ): String;
procedure flush_all;
procedure Delete(Key: string );
procedure connect;
property connected : Boolean read Fconnected write Setconnected;
property error : String read Ferror write Seterror;
property content : String read Fcontent write Setcontent;
End;
implementation
uses system.dateutils;
{ TmemcacheClass }
procedure TmemcacheClass.connect;
begin
try
if not tcp.Connected then
begin
tcp.Connect;
Fconnected:=true;
end;
except
on e: Exception do
begin
reportError(e.Message);
Fconnected:=false;
end;
end;
end;
constructor TmemcacheClass.create(ip: string );
begin
// FConnectTimeout := 4000;
Fconnected:=false;
tcp := TIdTCPClient.Create;
tcp.ConnectTimeout := 1000; // maybe to long , specially if there is a issue...
tcp.ReadTimeout := 2000;
tcp.Host := ip;
tcp.Port := 11211;
tcp.ReuseSocket := rsTrue;
end;
procedure TmemcacheClass.Delete(Key: string);
var
command : String;
stop : Boolean;
line : String;
begin
connect; // just in case
if Fconnected then
begin
command :='delete '+key;
tcp.Socket.Writeln(command);
stop:=false;
repeat
line:= tcp.Socket.ReadLn();
if Line = 'END' then Stop:=true;
if Line = 'DELETED' then Stop:=true;
if Line = 'NOT_FOUND' then Stop:=true;
if (Line = '') and ( not tcp.Socket.ReadLnTimedOut) then Stop:=true;
until Stop;
end;
end;
destructor TmemcacheClass.Destroy;
begin
tcp.Free;
inherited;
end;
procedure TmemcacheClass.flush_all;
var
command : String;
stop : Boolean;
line : String;
begin
Ferror := '';
connect; // just in case
if Fconnected then
begin
command :='flush_all';
try
tcp.Socket.Writeln(command);
except
on e: Exception do
begin
reportError(e.Message);
exit;
end;
end;
stop:=false;
repeat
try
line:= tcp.Socket.ReadLn();
except
on e: Exception do
begin
reportError(e.Message);
exit;
end;
end;
if Line = 'OK' then Stop:=true;
if Line = 'END' then Stop:=true;
if Line = 'STORED' then Stop:=true;
if (Line = '') and ( not tcp.Socket.ReadLnTimedOut) then Stop:=true;
until Stop;
if line <> 'STORED' then line:= tcp.Socket.ReadLn();
end;
end;
function TmemcacheClass.Lookup(Key : string): String;
var
Top : Boolean;
TopString : String;
line : String;
Data : String;
Stop : Boolean;
max_loops : Integer;
topStringValues : Tstringlist;
command : String;
size : Integer;
begin
Ferror := '';
connect; // just in case
result:='';
if Fconnected then
begin
command :='get '+key;
try
tcp.Socket.Writeln(command);
except
on e: Exception do
begin
reportError(e.Message);
exit;
result:='';
end;
end;
Top:=true;
stop := False;
data :='';
max_loops:=0;
size :=0;
repeat
inc(max_loops);
if top then
begin
tcp.Socket.MaxLineLength:=1700; // default first line :-)
try
TopString:= tcp.Socket.ReadLn();
except
on e: Exception do
begin
reportError(e.Message);
exit;
result:='';
end;
end;
top :=false;
if TopString = 'END' then Stop:=true;
if TopString = 'STORED' then Stop:=true;
if TopString = 'SERVER_ERROR' then
begin
Stop:=true;
reportError('SERVER_ERROR : '+key);
end;
if TopString = 'CLIENT_ERROR' then
begin
Stop:=true;
reportError('CLIENT_ERROR : '+key);
end;
if (TopString = '') and ( not tcp.Socket.ReadLnTimedOut) then Stop:=true;
if stop=false then
begin
// Decode top string
topStringValues := Tstringlist.Create;
try
TopString:= StringReplace(TopString,' ','*',[rfReplaceAll]);
topStringValues.Delimiter:='*';
topStringValues.DelimitedText:=TopString;
if topStringValues.Count=4 then
begin
size:=strtointdef( topStringValues[3],1700);
tcp.Socket.MaxLineLength:=size+10; // meassure length add 10 in case :-) for reading
end
else
begin
// error with header
stop:=true;
result:='';
data :='';
end;
finally
topStringValues.Clear;
topStringValues.Free;
end
end;
end
else
begin
try
Line := tcp.Socket.ReadLn(); // Can be to long need to check with a stream...
except
on e: Exception do
begin
reportError(e.Message);
exit;
result:='';
end;
end;
if Line = 'END' then Stop:=true;
if Line = 'STORED' then Stop:=true;
if (Line = '') and ( not tcp.Socket.ReadLnTimedOut) then Stop:=true;
if not stop then data := data+line;
end;
if max_loops > 5000 then
begin
stop :=true;
reportError('max_loops > 500 getting : '+key);
exit;
end;
until stop;
result:=data;
end;
end;
procedure TmemcacheClass.reportError(e: string);
begin
Ferror:=e;
tcp.Disconnect;
Fconnected:=false;
Fcontent:='';
end;
procedure TmemcacheClass.Setconnected(const Value: Boolean);
begin
Fconnected := Value;
end;
procedure TmemcacheClass.Setcontent(const Value: String);
begin
Fcontent := Value;
end;
procedure TmemcacheClass.Seterror(const Value: String);
begin
Ferror := Value;
end;
procedure TmemcacheClass.store(Key, Value: string );
var
command : String;
stop : Boolean;
line : String;
start_time : Extended ;
startLabel : String;
begin
start_time:= now;
Ferror := '';
connect; // just in case
if Fconnected then
begin
command :='set '+key+' 0 0 '+length(Value).ToString;
try
tcp.Socket.Writeln(command);
tcp.Socket.Writeln(Value);
except
on e: Exception do
begin
reportError(e.Message);
exit;
end;
end;
stop:=false;
repeat
try
line:= tcp.Socket.ReadLn();
except
on e: Exception do
begin
reportError(e.Message);
exit;
end;
end;
if Line = 'END' then Stop:=true;
if Line = 'STORED' then Stop:=true;
if (Line = '') and ( not tcp.Socket.ReadLnTimedOut) then Stop:=true;
until Stop;
startLabel:=(MilliSecondsBetween(Now, start_time) ).ToString;
startLabel:=startLabel;
if line <> 'STORED' then line:= tcp.Socket.ReadLn();
end;
end;
end.
I changed the store procedure.我改变了存储过程。 Added "noreply" to my command.
在我的命令中添加了“noreply”。 And comment out the reply readln.
并将回复 readln 注释掉。
Now it only takes 0 to 1 ms to store new data.现在存储新数据只需要 0 到 1 毫秒。 Dramatic upgrade in speed after fluch_all is used in memcached, and it need to rebuild.
memcached使用fluch_all后速度大幅提升,需要rebuild。
procedure TmemcacheClass.store(Key, Value: string );
var
command : String;
stop : Boolean;
line : String;
start_time : Extended ;
startLabel : String;
begin
start_time:= now;
Ferror := '';
connect; // just in case
if Fconnected then
begin
command :='set '+key+' 0 0 '+length(Value).ToString+' noreply';
try
tcp.Socket.Writeln(command);
tcp.Socket.Writeln(Value);
except
on e: Exception do
begin
reportError(e.Message);
exit;
end;
end;
// stop:=false;
// repeat
// try
// line:= tcp.Socket.ReadLn();
// except
// on e: Exception do
// begin
// reportError(e.Message);
// exit;
// end;
// end;
//
//
//
// if Line = 'END' then Stop:=true;
// if Line = 'STORED' then Stop:=true;
// if (Line = '') and ( not tcp.Socket.ReadLnTimedOut) then Stop:=true;
// until Stop;
// startLabel:=(MilliSecondsBetween(Now, start_time) ).ToString;
// startLabel:=startLabel;
//
// if line <> 'STORED' then line:= tcp.Socket.ReadLn();
end;
end;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.