【发布时间】:2019-12-27 14:49:43
【问题描述】:
我创建了一个 TmemcacheClass 类,我可以在其中设置和获取 memcached 的值。
它在 Delphi Webbroker 应用程序中使用,每个线程打开 TmemcacheClass 并在其生命周期中使用它。这意味着每个线程都打开 TIdTCPClient,并连接它并为每个请求重用。
获取值非常快,例如 0 到 1 毫秒 设置值也很快,比如 1 毫秒,但是设置后等待 readln 需要 47 毫秒。
任何想法如何加快这一点。
是等待很慢的过程 store()
行:= tcp.Socket.ReadLn();
添加孔单元,也许我可以在保存后删除 readln 以加快速度? 如果我放弃 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.
【问题讨论】:
-
您确定减速是在客户端吗?您是否嗅探过网络流量以查看服务器实际响应所需的时间?
-
嗨,雷米,谢谢。我不确定,但我正在本地机器上进行测试,并且 memcached 正在 ubuntu vmware 上运行。不确定如何从 ubuntu 测试延迟。如果我 telnet 似乎超快,但无法像使用 Delphi 一样测量这一点。但它可能是memcached在存储一个项目后响应缓慢。
-
我在 memcavhed "noreply" 中找到了 set 的这个新选项,我将对其进行测试 "set test1 0 0 4 noreply" 我将返回结果。