Multithreading 线程内同一IdHTTP上的多个请求
我有一个应用程序,每天发出数千个HTTP请求。 为了获得最佳性能,我决定只创建一次IdHTTP对象,并对所有请求使用相同的对象。 这就是问题的开始。在为每个请求创建一个IdHTTP时,一切都很顺利。 代码非常基本:Multithreading 线程内同一IdHTTP上的多个请求,multithreading,delphi,idhttp,Multithreading,Delphi,Idhttp,我有一个应用程序,每天发出数千个HTTP请求。 为了获得最佳性能,我决定只创建一次IdHTTP对象,并对所有请求使用相同的对象。 这就是问题的开始。在为每个请求创建一个IdHTTP时,一切都很顺利。 代码非常基本: constructor HTTPThread.Create; begin inherited Create(false); httpObject:= TIdHTTP.Create(Nil); sslObject:= TIdSSLIOHandlerSocketOpenSSL
constructor HTTPThread.Create;
begin
inherited Create(false);
httpObject:= TIdHTTP.Create(Nil);
sslObject:= TIdSSLIOHandlerSocketOpenSSL.Create(Nil);
sslObject.SSLOptions.Method:= sslvTLSv1_2;
httpObject.IOHandler:= sslObject;
httpObject.Request.Accept:= frmHTTPRequests.Edit1.Text;
httpObject.Request.UserAgent:= frmHTTPRequests.Edit3.Text;
httpObject.ReadTimeout:= 15000;
httpObject.HandleRedirects:= true;
FreeOnTerminate:= true;
OnTerminate:= TerminateProc;
end;
procedure HTTPThread.DoRequests;
var
htmlSource: string;
begin
try
htmlSource:= httpObject.Get(Link);
//a bunch of other stuff with HTML source
except
on E : Exception do
Synchronize(procedure
begin
errorList.Add(E.Message);
errorList.SaveToFile('Error.txt');
end);
end;
end;
我创建了这个,除了保存Error.txt文件来观察正在发生的事情。。。
代码有时在前1k请求中运行良好,有时在前2k中运行良好,但情况有所不同。突然,它开始在TXT文件上写入相同的错误:
对等方重置连接。domain.com-套接字错误#10054
我试图断开httpObject的连接,尝试了httpObject.Request.Clear,似乎什么都不起作用。
有没有可能做到这一点?由于某些原因,当服务器响应对等方的连接重置时,Indy没有关闭套接字,所以您需要手动执行此操作
procedure HTTPThread.DoRequests;
const
MAX_TRIES_COUNT = 5;
var
htmlSource: string;
TriesCount: Integer;
begin
TriesCount := 0;
repeat
try
htmlSource:= httpObject.Get(Link);
//a bunch of other stuff with HTML source
except
on E: Exception do
begin
if E.Message.Contains('by peer') then
begin
httpObject.Disconnect;
// Try to solve network connection issues
Continue;
end
else
begin
// Some other error handlers
end;
end;
inc(TriesCount);
end;
until (httpObject.ResponseCode = 200) or (TriesCount > MAX_TRIES_COUNT);
end;
另外,我不建议您使用
Synchronize()
进行线程同步。尝试使用或来代替。我在TIdHttp中遇到类似问题,我的解决方案是在出现错误时重新创建组件,然后重试。只有当第二次尝试也失败时,它才被视为实际问题。与执行实际请求相比,您是否实际测量了创建对象所需的时间和开销?我认为收益可以忽略不计,除非所有请求都指向同一台服务器,并且您可以利用keep alive连接的使用。@GolezTrol我没有检查。。。谢谢你的洞察力。@HeartWare好的。。。很高兴知道这是一个常见问题。“出于某些原因,当服务器响应“对等方重置连接”“时,Indy不会关闭套接字”-实际上,TIdHTTP
会在套接字错误时关闭套接字,如果服务器不同意使用保持活动状态,也会在每个请求结束时关闭套接字(无论成功还是失败)。“如果E.Message.Contains('by peer'),那么…
”-不要这样做。更好的方法是这样做:如果(E是EIdSocketError)和(EIdSocketError(E).LastError=10054)然后…
,或者:在E:EidSocketError上,如果E.LastError=10054,那么一定要开始,然后…结束;
。不要依赖消息检查,它们效率低下而且容易本地化。@RemyLebeau,Indy消息是不变的,至少现在是这样。我很久以前就发现了这个解决方案,我不清楚为什么我决定使用c检查文本消息而不是代码,但我相信这是有原因的。我想,你同意Indy错误地处理了这个错误(不仅仅是这个)。@OlvinRoght“Indy消息是不变的,至少现在是这样”——Indy的文本消息存储在资源字符串中,因此会受到用户本地化的影响。”我认为,你同意Indy错误地处理了这个错误”-我不同意这个说法,因为它与TIdHTTP
的源代码不匹配。@RemyLebeau发生这样的错误时,我不应该手动断开它。这应该在Indy内部的某个地方完成。