Multithreading 线程内同一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

我有一个应用程序,每天发出数千个HTTP请求。 为了获得最佳性能,我决定只创建一次IdHTTP对象,并对所有请求使用相同的对象。 这就是问题的开始。在为每个请求创建一个IdHTTP时,一切都很顺利。 代码非常基本:

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内部的某个地方完成。